Merge m-c to f-t, a=release-me-from-the-tyranny-of-this-hook
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 04 Jul 2016 11:17:28 -0700
changeset 303687 fdffe351484e4abbd32f686424ff840ae05f0992
parent 303591 a46d234975d9455d70a8b0db69c46c7a0141b2c5 (current diff)
parent 303560 f378a56b25ce2a2997b263c1857629f3f18d7400 (diff)
child 303688 a7105b09ae0c18b858c33b1020bdded6a6d66c9b
push id79141
push usercbook@mozilla.com
push dateTue, 05 Jul 2016 14:07:42 +0000
treeherdermozilla-inbound@f08c54971dd1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrelease-me-from-the-tyranny-of-this-hook
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to f-t, a=release-me-from-the-tyranny-of-this-hook
--- a/browser/components/migration/AutoMigrate.jsm
+++ b/browser/components/migration/AutoMigrate.jsm
@@ -95,38 +95,38 @@ const AutoMigrate = {
     return migrator;
   },
 
   /**
    * Pick a source profile (from the original browser) to use.
    *
    * @param {Migrator} migrator     the migrator object to use
    * @param {String}   suggestedId  the id of the profile to migrate, if pre-specified, or null
-   * @returns                       the id of the profile to migrate, or null if migrating
+   * @returns                       the profile to migrate, or null if migrating
    *                                from the default profile.
    */
   pickProfile(migrator, suggestedId) {
     let profiles = migrator.sourceProfiles;
     if (profiles && !profiles.length) {
       throw new Error("No profile data found to migrate.");
     }
     if (suggestedId) {
       if (!profiles) {
         throw new Error("Profile specified but only a default profile found.");
       }
       let suggestedProfile = profiles.find(profile => profile.id == suggestedId);
       if (!suggestedProfile) {
         throw new Error("Profile specified was not found.");
       }
-      return suggestedProfile.id;
+      return suggestedProfile;
     }
     if (profiles && profiles.length > 1) {
       throw new Error("Don't know how to pick a profile when more than 1 profile is present.");
     }
-    return profiles ? profiles[0].id : null;
+    return profiles ? profiles[0] : null;
   },
 
   getUndoRange() {
     let start, finish;
     try {
       start = parseInt(Services.prefs.getCharPref(kAutoMigrateStartedPref), 10);
       finish = parseInt(Services.prefs.getCharPref(kAutoMigrateFinishedPref), 10);
     } catch (ex) {
--- a/browser/components/migration/tests/unit/test_automigration.js
+++ b/browser/components/migration/tests/unit/test_automigration.js
@@ -61,40 +61,42 @@ add_task(function* checkMigratorPicking(
 });
 
 
 /**
  * Test automatically picking a profile to migrate from
  */
 add_task(function* checkProfilePicking() {
   let fakeMigrator = {sourceProfiles: [{id: "a"}, {id: "b"}]};
+  let profB = fakeMigrator.sourceProfiles[1];
   Assert.throws(() => AutoMigrate.pickProfile(fakeMigrator),
                 /Don't know how to pick a profile when more/,
                 "Should throw when there are multiple profiles.");
   Assert.throws(() => AutoMigrate.pickProfile(fakeMigrator, "c"),
                 /Profile specified was not found/,
                 "Should throw when the profile supplied doesn't exist.");
   let profileToMigrate = AutoMigrate.pickProfile(fakeMigrator, "b");
-  Assert.equal(profileToMigrate, "b", "Should return profile supplied");
+  Assert.equal(profileToMigrate, profB, "Should return profile supplied");
 
   fakeMigrator.sourceProfiles = null;
   Assert.throws(() => AutoMigrate.pickProfile(fakeMigrator, "c"),
                 /Profile specified but only a default profile found./,
                 "Should throw when the profile supplied doesn't exist.");
   profileToMigrate = AutoMigrate.pickProfile(fakeMigrator);
   Assert.equal(profileToMigrate, null, "Should return default profile when that's the only one.");
 
   fakeMigrator.sourceProfiles = [];
   Assert.throws(() => AutoMigrate.pickProfile(fakeMigrator),
                 /No profile data found/,
                 "Should throw when no profile data is present.");
 
   fakeMigrator.sourceProfiles = [{id: "a"}];
+  let profA = fakeMigrator.sourceProfiles[0];
   profileToMigrate = AutoMigrate.pickProfile(fakeMigrator);
-  Assert.equal(profileToMigrate, "a", "Should return the only profile if only one is present.");
+  Assert.equal(profileToMigrate, profA, "Should return the only profile if only one is present.");
 });
 
 /**
  * Test the complete automatic process including browser and profile selection,
  * and actual migration (which implies startup)
  */
 add_task(function* checkIntegration() {
   gShimmedMigrator = {
--- a/browser/components/newtab/NewTabSearchProvider.jsm
+++ b/browser/components/newtab/NewTabSearchProvider.jsm
@@ -22,37 +22,28 @@ XPCOMUtils.defineLazyGetter(this, "Event
 
 function SearchProvider() {
   EventEmitter.decorate(this);
 }
 
 SearchProvider.prototype = {
 
   observe(subject, topic, data) { // jshint unused:false
-    switch (data) {
-      case "engine-current":
-        if (topic === CURRENT_ENGINE) {
-          Task.spawn(function* () {
-            try {
-              let state = yield ContentSearch.currentStateObj(true);
-              let engine = state.currentEngine;
-              this.emit(CURRENT_ENGINE, engine);
-            } catch (e) {
-              Cu.reportError(e);
-            }
-          }.bind(this));
+    // all other topics are not relevant to content searches and can be
+    // ignored by NewTabSearchProvider
+    if (data === "engine-current" && topic === CURRENT_ENGINE) {
+      Task.spawn(function* () {
+        try {
+          let state = yield ContentSearch.currentStateObj(true);
+          let engine = state.currentEngine;
+          this.emit(CURRENT_ENGINE, engine);
+        } catch (e) {
+          Cu.reportError(e);
         }
-        break;
-      case "engine-default":
-        // engine-default is always sent with engine-current and isn't
-        // relevant to content searches.
-        break;
-      default:
-        Cu.reportError(new Error("NewTabSearchProvider observing unknown topic"));
-        break;
+      }.bind(this));
     }
   },
 
   init() {
     try {
       Services.obs.addObserver(this, CURRENT_ENGINE, true);
     } catch (e) {
       Cu.reportError(e);
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -2928,20 +2928,24 @@ var SessionStoreInternal = {
     let numVisibleTabs = 0;
 
     for (var t = 0; t < newTabCount; t++) {
       // When trying to restore into existing tab, we also take the userContextId
       // into account if present.
       let userContextId = winData.tabs[t].userContextId;
       let reuseExisting = t < openTabCount &&
                           (tabbrowser.tabs[t].getAttribute("usercontextid") == (userContextId || ""));
+      // If the tab is pinned, then we'll be loading it right away, and
+      // there's no need to cause a remoteness flip by loading it initially
+      // non-remote.
+      let forceNotRemote = !winData.tabs[t].pinned;
       let tab = reuseExisting ? tabbrowser.tabs[t] :
                                 tabbrowser.addTab("about:blank",
                                                   {skipAnimation: true,
-                                                   forceNotRemote: true,
+                                                   forceNotRemote,
                                                    userContextId});
 
       // If we inserted a new tab because the userContextId didn't match with the
       // open tab, even though `t < openTabCount`, we need to remove that open tab
       // and put the newly added tab in its place.
       if (!reuseExisting && t < openTabCount) {
         tabbrowser.removeTab(tabbrowser.tabs[t]);
         tabbrowser.moveTabTo(tab, t);
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -266,17 +266,19 @@ KeyframeEffectReadOnly::GetComputedTimin
   if (localTime >=
         std::min(StickyTimeDuration(aTiming.mDelay + result.mActiveDuration),
                  result.mEndTime)) {
     result.mPhase = ComputedTiming::AnimationPhase::After;
     if (!result.FillsForwards()) {
       // The animation isn't active or filling at this time.
       return result;
     }
-    activeTime = result.mActiveDuration;
+    activeTime = std::max(std::min(result.mActiveDuration,
+                                   result.mActiveDuration + aTiming.mEndDelay),
+                          zeroDuration);
   } else if (localTime <
                std::min(StickyTimeDuration(aTiming.mDelay), result.mEndTime)) {
     result.mPhase = ComputedTiming::AnimationPhase::Before;
     if (!result.FillsBackwards()) {
       // The animation isn't active or filling at this time.
       return result;
     }
     // activeTime is zero
@@ -316,19 +318,29 @@ KeyframeEffectReadOnly::GetComputedTimin
   // simply iteration progress.
   // https://w3c.github.io/web-animations/#simple-iteration-progress
   double progress = IsFinite(overallProgress)
                     ? fmod(overallProgress, 1.0)
                     : fmod(result.mIterationStart, 1.0);
 
   // When we finish exactly at the end of an iteration we need to report
   // the end of the final iteration and not the start of the next iteration.
+  // We *don't* want to do this when we have a zero-iteration animation or
+  // when the animation has been effectively made into a zero-duration animation
+  // using a negative end-delay, however.
   if (result.mPhase == ComputedTiming::AnimationPhase::After &&
       progress == 0.0 &&
-      result.mIterations != 0.0) {
+      result.mIterations != 0.0 &&
+      (activeTime != zeroDuration || result.mDuration == zeroDuration)) {
+    // The only way we can be in the after phase with a progress of zero and
+    // a current iteration of zero, is if we have a zero iteration count or
+    // were clipped using a negative end delay--both of which we should have
+    // detected above.
+    MOZ_ASSERT(result.mCurrentIteration != 0,
+               "Should not have zero current iteration");
     progress = 1.0;
     if (result.mCurrentIteration != UINT64_MAX) {
       result.mCurrentIteration--;
     }
   }
 
   // Factor in the direction.
   bool thisIterationReverse = false;
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -26,17 +26,18 @@
 namespace mozilla {
 
 class ContainerParser;
 class MediaByteBuffer;
 class MediaRawData;
 class MediaSourceDemuxer;
 class SourceBufferResource;
 
-class SourceBufferTaskQueue {
+class SourceBufferTaskQueue
+{
 public:
   SourceBufferTaskQueue()
   : mMonitor("SourceBufferTaskQueue")
   {}
   ~SourceBufferTaskQueue()
   {
     MOZ_ASSERT(mQueue.IsEmpty(), "All tasks must have been processed");
   }
@@ -64,17 +65,18 @@ public:
     return mQueue.Length();
   }
 
 private:
   mutable Monitor mMonitor;
   nsTArray<RefPtr<SourceBufferTask>> mQueue;
 };
 
-class TrackBuffersManager {
+class TrackBuffersManager
+{
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackBuffersManager);
 
   enum class EvictDataResult : int8_t
   {
     NO_DATA_EVICTED,
     CANT_EVICT,
     BUFFER_FULL,
@@ -158,17 +160,17 @@ public:
 
   void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes);
 
 private:
   typedef MozPromise<bool, nsresult, /* IsExclusive = */ true> CodedFrameProcessingPromise;
 
   // for MediaSourceDemuxer::GetMozDebugReaderData
   friend class MediaSourceDemuxer;
-  virtual ~TrackBuffersManager();
+  ~TrackBuffersManager();
   // All following functions run on the taskqueue.
   RefPtr<AppendPromise> DoAppendData(RefPtr<MediaByteBuffer> aData,
                                      SourceBufferAttributes aAttributes);
   void ScheduleSegmentParserLoop();
   void SegmentParserLoop();
   void InitializationSegmentReceived();
   void ShutdownDemuxers();
   void CreateDemuxerforMIMEType();
@@ -247,17 +249,18 @@ private:
   void OnAudioDemuxFailed(DemuxerFailureReason aFailure)
   {
     mAudioTracks.mDemuxRequest.Complete();
     OnDemuxFailed(TrackType::kAudioTrack, aFailure);
   }
 
   void DoEvictData(const media::TimeUnit& aPlaybackTime, int64_t aSizeToEvict);
 
-  struct TrackData {
+  struct TrackData
+  {
     TrackData()
       : mNumTracks(0)
       , mNeedRandomAccessPoint(true)
       , mSizeBuffer(0)
     {}
     uint32_t mNumTracks;
     // Definition of variables:
     // https://w3c.github.io/media-source/#track-buffers
@@ -373,17 +376,18 @@ private:
       default:
         return mAudioTracks;
     }
   }
   TrackData mVideoTracks;
   TrackData mAudioTracks;
 
   // TaskQueue methods and objects.
-  AbstractThread* GetTaskQueue() {
+  AbstractThread* GetTaskQueue()
+  {
     return mTaskQueue;
   }
   bool OnTaskQueue()
   {
     return !GetTaskQueue() || GetTaskQueue()->IsCurrentThreadIn();
   }
   RefPtr<AutoTaskQueue> mTaskQueue;
 
--- a/dom/svg/SVGAnimatedPreserveAspectRatio.cpp
+++ b/dom/svg/SVGAnimatedPreserveAspectRatio.cpp
@@ -141,26 +141,17 @@ ToPreserveAspectRatio(const nsAString &a
       !tokenizer.hasMoreTokens()) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
   const nsAString &token = tokenizer.nextToken();
 
   nsresult rv;
   SVGPreserveAspectRatio val;
 
-  val.SetDefer(token.EqualsLiteral("defer"));
-
-  if (val.GetDefer()) {
-    if (!tokenizer.hasMoreTokens()) {
-      return NS_ERROR_DOM_SYNTAX_ERR;
-    }
-    rv = val.SetAlign(GetAlignForString(tokenizer.nextToken()));
-  } else {
-    rv = val.SetAlign(GetAlignForString(token));
-  }
+  rv = val.SetAlign(GetAlignForString(token));
 
   if (NS_FAILED(rv)) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   if (tokenizer.hasMoreTokens()) {
     rv = val.SetMeetOrSlice(GetMeetOrSliceForString(tokenizer.nextToken()));
     if (NS_FAILED(rv)) {
@@ -211,20 +202,16 @@ SVGAnimatedPreserveAspectRatio::SetBaseV
 void
 SVGAnimatedPreserveAspectRatio::GetBaseValueString(
   nsAString& aValueAsString) const
 {
   nsAutoString tmpString;
 
   aValueAsString.Truncate();
 
-  if (mBaseVal.mDefer) {
-    aValueAsString.AppendLiteral("defer ");
-  }
-
   GetAlignString(tmpString, mBaseVal.mAlign);
   aValueAsString.Append(tmpString);
 
   if (mBaseVal.mAlign != uint8_t(SVG_PRESERVEASPECTRATIO_NONE)) {
 
     aValueAsString.Append(' ');
     GetMeetOrSliceString(tmpString, mBaseVal.mMeetOrSlice);
     aValueAsString.Append(tmpString);
@@ -253,30 +240,28 @@ SVGAnimatedPreserveAspectRatio::SetBaseV
 }
 
 static uint64_t
 PackPreserveAspectRatio(const SVGPreserveAspectRatio& par)
 {
   // All preserveAspectRatio values are enum values (do not interpolate), so we
   // can safely collate them and treat them as a single enum as for SMIL.
   uint64_t packed = 0;
-  packed |= uint64_t(par.GetDefer() ? 1 : 0) << 16;
   packed |= uint64_t(par.GetAlign()) << 8;
   packed |= uint64_t(par.GetMeetOrSlice());
   return packed;
 }
 
 void
 SVGAnimatedPreserveAspectRatio::SetAnimValue(uint64_t aPackedValue,
                                              nsSVGElement *aSVGElement)
 {
   if (mIsAnimated && PackPreserveAspectRatio(mAnimVal) == aPackedValue) {
     return;
   }
-  mAnimVal.SetDefer(((aPackedValue & 0xff0000) >> 16) ? true : false);
   mAnimVal.SetAlign(uint16_t((aPackedValue & 0xff00) >> 8));
   mAnimVal.SetMeetOrSlice(uint16_t(aPackedValue & 0xff));
   mIsAnimated = true;
   aSVGElement->DidAnimatePreserveAspectRatio();
 }
 
 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
 SVGAnimatedPreserveAspectRatio::ToDOMAnimatedPreserveAspectRatio(
--- a/dom/svg/SVGAnimatedPreserveAspectRatio.h
+++ b/dom/svg/SVGAnimatedPreserveAspectRatio.h
@@ -23,17 +23,16 @@ class SVGAnimationElement;
 } // namespace dom
 
 class SVGAnimatedPreserveAspectRatio final
 {
 public:
   void Init() {
     mBaseVal.mAlign = SVG_PRESERVEASPECTRATIO_XMIDYMID;
     mBaseVal.mMeetOrSlice = SVG_MEETORSLICE_MEET;
-    mBaseVal.mDefer = false;
     mAnimVal = mBaseVal;
     mIsAnimated = false;
     mIsBaseSet = false;
   }
 
   nsresult SetBaseValueString(const nsAString& aValue,
                               nsSVGElement *aSVGElement,
                               bool aDoSetAttr);
@@ -41,29 +40,27 @@ public:
 
   void SetBaseValue(const SVGPreserveAspectRatio &aValue,
                     nsSVGElement *aSVGElement);
   nsresult SetBaseAlign(uint16_t aAlign, nsSVGElement *aSVGElement) {
     if (aAlign < SVG_ALIGN_MIN_VALID || aAlign > SVG_ALIGN_MAX_VALID) {
       return NS_ERROR_FAILURE;
     }
     SetBaseValue(SVGPreserveAspectRatio(
-                   static_cast<SVGAlign>(aAlign), mBaseVal.GetMeetOrSlice(),
-                   mBaseVal.GetDefer()),
+                   static_cast<SVGAlign>(aAlign), mBaseVal.GetMeetOrSlice()),
                  aSVGElement);
     return NS_OK;
   }
   nsresult SetBaseMeetOrSlice(uint16_t aMeetOrSlice, nsSVGElement *aSVGElement) {
     if (aMeetOrSlice < SVG_MEETORSLICE_MIN_VALID ||
         aMeetOrSlice > SVG_MEETORSLICE_MAX_VALID) {
       return NS_ERROR_FAILURE;
     }
     SetBaseValue(SVGPreserveAspectRatio(
-                   mBaseVal.GetAlign(), static_cast<SVGMeetOrSlice>(aMeetOrSlice),
-                   mBaseVal.GetDefer()),
+                   mBaseVal.GetAlign(), static_cast<SVGMeetOrSlice>(aMeetOrSlice)),
                  aSVGElement);
     return NS_OK;
   }
   void SetAnimValue(uint64_t aPackedValue, nsSVGElement *aSVGElement);
 
   const SVGPreserveAspectRatio &GetBaseValue() const
     { return mBaseVal; }
   const SVGPreserveAspectRatio &GetAnimValue() const
--- a/dom/svg/SVGPreserveAspectRatio.cpp
+++ b/dom/svg/SVGPreserveAspectRatio.cpp
@@ -20,18 +20,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 bool
 SVGPreserveAspectRatio::operator==(const SVGPreserveAspectRatio& aOther) const
 {
   return mAlign == aOther.mAlign &&
-    mMeetOrSlice == aOther.mMeetOrSlice &&
-    mDefer == aOther.mDefer;
+    mMeetOrSlice == aOther.mMeetOrSlice;
 }
 
 JSObject*
 DOMSVGPreserveAspectRatio::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return mozilla::dom::SVGPreserveAspectRatioBinding::Wrap(aCx, this, aGivenProto);
 }
 
--- a/dom/svg/SVGPreserveAspectRatio.h
+++ b/dom/svg/SVGPreserveAspectRatio.h
@@ -48,29 +48,26 @@ const uint16_t SVG_MEETORSLICE_MIN_VALID
 const uint16_t SVG_MEETORSLICE_MAX_VALID = SVG_MEETORSLICE_SLICE;
 
 class SVGAnimatedPreserveAspectRatio;
 
 class SVGPreserveAspectRatio final
 {
   friend class SVGAnimatedPreserveAspectRatio;
 public:
-  SVGPreserveAspectRatio(SVGAlign aAlign, SVGMeetOrSlice aMeetOrSlice,
-                         bool aDefer = false)
+  SVGPreserveAspectRatio(SVGAlign aAlign, SVGMeetOrSlice aMeetOrSlice)
     : mAlign(aAlign)
     , mMeetOrSlice(aMeetOrSlice)
-    , mDefer(aDefer)
   {}
 
   bool operator==(const SVGPreserveAspectRatio& aOther) const;
 
   explicit SVGPreserveAspectRatio()
     : mAlign(SVG_PRESERVEASPECTRATIO_UNKNOWN)
     , mMeetOrSlice(SVG_MEETORSLICE_UNKNOWN)
-    , mDefer(false)
   {}
 
   nsresult SetAlign(uint16_t aAlign) {
     if (aAlign < SVG_ALIGN_MIN_VALID || aAlign > SVG_ALIGN_MAX_VALID)
       return NS_ERROR_FAILURE;
     mAlign = static_cast<uint8_t>(aAlign);
     return NS_OK;
   }
@@ -86,33 +83,24 @@ public:
     mMeetOrSlice = static_cast<uint8_t>(aMeetOrSlice);
     return NS_OK;
   }
 
   SVGMeetOrSlice GetMeetOrSlice() const {
     return static_cast<SVGMeetOrSlice>(mMeetOrSlice);
   }
 
-  void SetDefer(bool aDefer) {
-    mDefer = aDefer;
-  }
-
-  bool GetDefer() const {
-    return mDefer;
-  }
-
   uint32_t Hash() const {
-    return HashGeneric(mAlign, mMeetOrSlice, mDefer);
+    return HashGeneric(mAlign, mMeetOrSlice);
   }
 
 private:
   // We can't use enum types here because some compilers fail to pack them.
   uint8_t mAlign;
   uint8_t mMeetOrSlice;
-  bool mDefer;
 };
 
 namespace dom {
 
 class DOMSVGPreserveAspectRatio final : public nsISupports,
                                         public nsWrapperCache
 {
 public:
--- a/dom/svg/SVGSVGElement.cpp
+++ b/dom/svg/SVGSVGElement.cpp
@@ -1117,20 +1117,16 @@ SVGSVGElement::
     // want that.  Need to tell ourselves to flush our transform.
     mImageNeedsTransformInvalidation = true;
   }
 
   if (!hasViewBoxRect) {
     return; // preserveAspectRatio irrelevant (only matters if we have viewBox)
   }
 
-  if (aPAR.GetDefer() && HasPreserveAspectRatio()) {
-    return; // Referring element defers to my own preserveAspectRatio value.
-  }
-
   if (SetPreserveAspectRatioProperty(aPAR)) {
     mImageNeedsTransformInvalidation = true;
   }
 }
 
 void
 SVGSVGElement::ClearImageOverridePreserveAspectRatio()
 {
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -220,30 +220,30 @@ partial interface Document {
 };
 
 // https://fullscreen.spec.whatwg.org/#api
 partial interface Document {
   // Note: Per spec the 'S' in these two is lowercase, but the "Moz"
   // versions have it uppercase.
   [LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   readonly attribute boolean fullscreen;
-  [BinaryName="fullscreen", Deprecated="PrefixedFullscreenAPI"]
+  [BinaryName="fullscreen"]
   readonly attribute boolean mozFullScreen;
   [LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   readonly attribute boolean fullscreenEnabled;
-  [BinaryName="fullscreenEnabled", Deprecated="PrefixedFullscreenAPI"]
+  [BinaryName="fullscreenEnabled"]
   readonly attribute boolean mozFullScreenEnabled;
   [LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   readonly attribute Element? fullscreenElement;
-  [BinaryName="fullscreenElement", Deprecated="PrefixedFullscreenAPI"]
+  [BinaryName="fullscreenElement"]
   readonly attribute Element? mozFullScreenElement;
 
   [Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   void exitFullscreen();
-  [BinaryName="exitFullscreen", Deprecated="PrefixedFullscreenAPI"]
+  [BinaryName="exitFullscreen"]
   void mozCancelFullScreen();
 
   // Events handlers
   [Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   attribute EventHandler onfullscreenchange;
   [Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   attribute EventHandler onfullscreenerror;
 };
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -256,11 +256,11 @@ dictionary RequestFullscreenOptions {
 // https://fullscreen.spec.whatwg.org/#api
 partial interface Element {
   /**
    * The options parameter is non-standard. In Gecko, it can be:
    *  a RequestFullscreenOptions object
    */
   [Throws, UnsafeInPrerendering, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   void requestFullscreen(optional any options);
-  [Throws, UnsafeInPrerendering, BinaryName="requestFullscreen", Deprecated="PrefixedFullscreenAPI"]
+  [Throws, UnsafeInPrerendering, BinaryName="requestFullscreen"]
   void mozRequestFullScreen(optional any options);
 };
--- a/gfx/config/gfxFeature.h
+++ b/gfx/config/gfxFeature.h
@@ -15,16 +15,17 @@
 namespace mozilla {
 namespace gfx {
 
 #define GFX_FEATURE_MAP(_)                                                        \
   /* Name,                        Type,         Description */                    \
   _(HW_COMPOSITING,               Feature,      "Compositing")                    \
   _(D3D11_COMPOSITING,            Feature,      "Direct3D11 Compositing")         \
   _(D3D9_COMPOSITING,             Feature,      "Direct3D9 Compositing")          \
+  _(OPENGL_COMPOSITING,           Feature,      "OpenGL Compositing")             \
   _(DIRECT2D,                     Feature,      "Direct2D")                       \
   _(D3D11_HW_ANGLE,               Feature,      "Direct3D11 hardware ANGLE")               \
   _(GPU_PROCESS,                  Feature,      "GPU Process")                    \
   /* Add new entries above this comment */
 
 enum class Feature : uint32_t {
 #define MAKE_ENUM(name, type, desc) name,
   GFX_FEATURE_MAP(MAKE_ENUM)
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -995,17 +995,16 @@ GLContextProviderEGL::CreateHeadless(Cre
 /*static*/ already_AddRefed<GLContext>
 GLContextProviderEGL::CreateOffscreen(const mozilla::gfx::IntSize& size,
                                       const SurfaceCaps& minCaps,
                                       CreateContextFlags flags,
                                       nsACString* const out_failureId)
 {
     bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
     if (!sEGLLibrary.EnsureInitialized(forceEnableHardware, out_failureId)) { // Needed for IsANGLE().
-        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_LIB_INIT");
         return nullptr;
     }
 
     bool canOffscreenUseHeadless = true;
     if (sEGLLibrary.IsANGLE()) {
         // ANGLE needs to use PBuffers.
         canOffscreenUseHeadless = false;
     }
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -116,19 +116,19 @@ public:
   bool Recv__delete__() override { return true; }
 
   ClientIPCAllocator* GetAllocator() { return mTextureForwarder; }
 
   void ActorDestroy(ActorDestroyReason why) override;
 
   bool IPCOpen() const { return mIPCOpen; }
 
-  void Lock() const { if (mCompositableForwarder->UsesImageBridge()) { mLock.Enter(); } }
+  void Lock() const { if (mCompositableForwarder && mCompositableForwarder->UsesImageBridge()) { mLock.Enter(); } }
 
-  void Unlock() const { if (mCompositableForwarder->UsesImageBridge()) { mLock.Leave(); } }
+  void Unlock() const { if (mCompositableForwarder && mCompositableForwarder->UsesImageBridge()) { mLock.Leave(); } }
 
 private:
 
   // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor
   // and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse.
   // The purpose of these methods is to be aware of when the IPC system around this
   // actor goes down: mIPCOpen is then set to false.
   void AddIPDLReference() {
@@ -907,16 +907,61 @@ TextureClient::InitIPDLActor(Compositabl
   // since it will be unlocked in TextureClient::Unlock.
   if (mIsLocked) {
     LockActor();
   }
 
   return mActor->IPCOpen();
 }
 
+bool
+TextureClient::InitIPDLActor(TextureForwarder* aForwarder, LayersBackend aBackend)
+{
+  MOZ_ASSERT(aForwarder && aForwarder->GetMessageLoop() == mAllocator->AsClientAllocator()->GetMessageLoop());
+  if (mActor && !mActor->mDestroyed) {
+    CompositableForwarder* currentFwd = mActor->mCompositableForwarder;
+    TextureForwarder* currentTexFwd = mActor->mTextureForwarder;
+
+    if (currentFwd) {
+      gfxCriticalError() << "Attempt to remove a texture from a CompositableForwarder.";
+      return false;
+    }
+
+    if (currentTexFwd && currentTexFwd != aForwarder) {
+      gfxCriticalError() << "Attempt to move a texture to a different channel.";
+      return false;
+    }
+    mActor->mTextureForwarder = aForwarder;
+    return true;
+  }
+  MOZ_ASSERT(!mActor || mActor->mDestroyed, "Cannot use a texture on several IPC channels.");
+
+  SurfaceDescriptor desc;
+  if (!ToSurfaceDescriptor(desc)) {
+    return false;
+  }
+
+  mActor = static_cast<TextureChild*>(aForwarder->CreateTexture(desc,
+    aBackend,
+    GetFlags(),
+    mSerial));
+  MOZ_ASSERT(mActor);
+  mActor->mTextureForwarder = aForwarder;
+  mActor->mTextureClient = this;
+  mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD);
+
+  // If the TextureClient is already locked, we have to lock TextureChild's mutex
+  // since it will be unlocked in TextureClient::Unlock.
+  if (mIsLocked) {
+    LockActor();
+  }
+
+  return mActor->IPCOpen();
+}
+
 PTextureChild*
 TextureClient::GetIPDLActor()
 {
   return mActor;
 }
 
 static inline gfx::BackendType
 BackendTypeForBackendSelector(LayersBackend aLayersBackend, BackendSelector aSelector)
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -544,22 +544,32 @@ public:
 
   /**
    * If this method retuns false, TextureClient is already added to CompositableClient,
    * since its creation or recycling.
    */
   bool IsAddedToCompositableClient() const { return mAddedToCompositableClient; }
 
   /**
-   * Create and init the TextureChild/Parent IPDL actor pair.
+  * Create and init the TextureChild/Parent IPDL actor pair
+  * with a CompositableForwarder.
+  *
+  * Should be called only once per TextureClient.
+  * The TextureClient must not be locked when calling this method.
+  */
+  bool InitIPDLActor(CompositableForwarder* aForwarder);
+
+  /**
+   * Create and init the TextureChild/Parent IPDL actor pair
+   * with a TextureForwarder.
    *
    * Should be called only once per TextureClient.
    * The TextureClient must not be locked when calling this method.
    */
-  bool InitIPDLActor(CompositableForwarder* aForwarder);
+  bool InitIPDLActor(TextureForwarder* aForwarder, LayersBackend aBackendType);
 
   /**
    * Return a pointer to the IPDLActor.
    *
    * This is to be used with IPDL messages only. Do not store the returned
    * pointer.
    */
   PTextureChild* GetIPDLActor();
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -772,16 +772,18 @@ gfxPlatform::Init()
     if (skiaCacheSize != kDefaultGlyphCacheSize) {
       SkGraphics::SetFontCacheLimit(skiaCacheSize);
     }
 #endif
 
     ScrollMetadata::sNullMetadata = new ScrollMetadata();
     ClearOnShutdown(&ScrollMetadata::sNullMetadata);
 
+    InitOpenGLConfig();
+
     if (obs) {
       obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr);
     }
 }
 
 static bool sLayersIPCIsUp = false;
 
 void
@@ -2346,52 +2348,23 @@ gfxPlatform::UseProgressivePaint()
 }
 
 /*static*/ bool
 gfxPlatform::PerfWarnings()
 {
   return gfxPrefs::PerfWarnings();
 }
 
-static inline bool
-AllowOpenGL(bool* aWhitelisted)
-{
-  nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
-  if (gfxInfo) {
-    // bug 655578: on X11 at least, we must always call GetData (even if we don't need that information)
-    // as that's what causes GfxInfo initialization which kills the zombie 'glxtest' process.
-    // initially we relied on the fact that GetFeatureStatus calls GetData for us, but bug 681026 showed
-    // that assumption to be unsafe.
-    gfxInfo->GetData();
-
-    int32_t status;
-    nsCString discardFailureId;
-    if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, discardFailureId, &status))) {
-      if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
-        *aWhitelisted = true;
-        return true;
-      }
-    }
-  }
-
-  return gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING);
-}
-
 void
 gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
 {
-  // Being whitelisted is not enough to accelerate, but not being whitelisted is
-  // enough not to:
-  bool whitelisted = false;
-
-  if (AllowOpenGL(&whitelisted)) {
+  if (gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING)) {
     aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
   }
-
-  if (!whitelisted) {
+  else {
     static int tell_me_once = 0;
     if (!tell_me_once) {
       NS_WARNING("OpenGL-accelerated layers are not supported on this system");
       tell_me_once = 1;
     }
 #ifdef MOZ_WIDGET_ANDROID
     NS_RUNTIMEABORT("OpenGL-accelerated layers are a hard requirement on this platform. "
                     "Cannot continue without support for them");
@@ -2466,8 +2439,58 @@ gfxPlatform::SupportsApzDragInput() cons
   return gfxPrefs::APZDragEnabled();
 }
 
 void
 gfxPlatform::BumpDeviceCounter()
 {
   mDeviceCounter++;
 }
+
+void
+gfxPlatform::InitOpenGLConfig()
+{
+  FeatureState& openGLFeature = gfxConfig::GetFeature(Feature::OPENGL_COMPOSITING);
+
+  // Check to see hw comp supported
+  if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
+    openGLFeature.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled",
+                           NS_LITERAL_CSTRING("FEATURE_FAILURE_OPENGL_NEED_HWCOMP"));
+    return;
+  }
+
+  #ifdef XP_WIN
+  // Don't enable by default on Windows, since it could show up in about:support even
+  // though it'll never get used.
+  openGLFeature.SetDefaultFromPref(
+    gfxPrefs::GetLayersPreferOpenGLPrefName(),
+    false,
+    gfxPrefs::GetLayersPreferOpenGLPrefDefault());
+  #else
+    openGLFeature.EnableByDefault();
+  #endif
+
+  nsCString message;
+  nsCString failureId;
+  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &message, failureId)) {
+    openGLFeature.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
+  }
+}
+
+bool
+gfxPlatform::IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage, nsCString& aFailureId)
+{
+  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+  if (!gfxInfo) {
+    return true;
+  }
+
+  int32_t status;    
+  if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) &&
+      status != nsIGfxInfo::FEATURE_STATUS_OK)
+  {
+    aOutMessage->AssignLiteral("#BLOCKLIST_");
+    aOutMessage->AppendASCII(aFailureId.get());
+    return false;
+  }
+
+  return true;
+}
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -649,16 +649,23 @@ public:
     virtual bool RequiresAcceleratedGLContextForCompositorOGL() const {
       return false;
     }
 
     uint64_t GetDeviceCounter() const {
       return mDeviceCounter;
     }
 
+    /**
+     * Check the blocklist for a feature. Returns false if the feature is blocked
+     * with an appropriate message and failure ID.
+     * */
+    static bool IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage,
+                                    nsCString& aFailureId);
+
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     virtual void InitAcceleration();
 
     /**
      * Initialized hardware vsync based on each platform.
@@ -745,16 +752,17 @@ protected:
     RefPtr<mozilla::gfx::DrawTarget> mScreenReferenceDrawTarget;
 
 private:
     /**
      * Start up Thebes.
      */
     static void Init();
 
+    static void InitOpenGLConfig();
     static void CreateCMSOutputProfile();
 
     static void GetCMSOutputProfileData(void *&mem, size_t &size);
 
     friend void RecordingPrefChanged(const char *aPrefName, void *aClosure);
 
     virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size);
 
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -635,16 +635,17 @@ public:
   }
 
   class GLXDisplay final : public VsyncSource::Display
   {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GLXDisplay)
 
   public:
     GLXDisplay() : mGLContext(nullptr)
+                 , mXDisplay(nullptr)
                  , mSetupLock("GLXVsyncSetupLock")
                  , mVsyncThread("GLXVsyncThread")
                  , mVsyncTask(nullptr)
                  , mVsyncEnabledLock("GLXVsyncEnabledLock")
                  , mVsyncEnabled(false)
     {
     }
 
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1893,35 +1893,16 @@ bool DoesD3D11TextureSharingWork(ID3D11D
   return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_B8G8R8A8_UNORM, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
 }
 
 bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device)
 {
   return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE);
 }
 
-static inline bool
-IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage, nsCString& aFailureId)
-{
-  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
-  if (!gfxInfo) {
-    return true;
-  }
-
-  int32_t status;
-  if (SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) &&
-      status != nsIGfxInfo::FEATURE_STATUS_OK)
-  {
-    aOutMessage->AssignLiteral("#BLOCKLIST_");
-    aOutMessage->AppendASCII(aFailureId.get());
-    return false;
-  }
-
-  return true;
-}
 
 static inline bool
 IsWARPStable()
 {
   // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703.
   if (!IsWin8OrLater() || GetModuleHandleA("nvdxgiwrap.dll")) {
     return false;
   }
@@ -1938,17 +1919,17 @@ InitializeANGLEConfig()
                                 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_DISABLED"));
     return;
   }
 
   d3d11ANGLE.EnableByDefault();
 
   nsCString message;
   nsCString failureId;
-  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, &message,
+  if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, &message,
                            failureId)) {
     d3d11ANGLE.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
   }
 
 }
 
 void
 gfxWindowsPlatform::InitializeConfig()
@@ -1987,17 +1968,17 @@ gfxWindowsPlatform::InitializeD3D9Config
 
     if (!d3d9.IsEnabled() && gfxPrefs::LayersPreferD3D9()) {
       d3d9.UserEnable("Direct3D9 enabled via layers.prefer-d3d9");
     }
   }
 
   nsCString message;
   nsCString failureId;
-  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &message,
+  if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &message,
                            failureId)) {
     d3d9.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
   }
 
   if (gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) {
     d3d9.UserForceEnable("Hardware compositing is force-enabled");
   }
 }
@@ -2021,17 +2002,17 @@ gfxWindowsPlatform::InitializeD3D11Confi
   if (gfxPrefs::LayersPreferD3D9()) {
     d3d11.UserDisable("Disabled due to user preference for Direct3D 9",
                       NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_PREF"));
     return;
   }
 
   nsCString message;
   nsCString failureId;
-  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &message, failureId)) {
+  if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &message, failureId)) {
     if (IsWARPStable() && !gfxPrefs::LayersD3D11DisableWARP()) {
       // We do not expect hardware D3D11 to work, so we'll try WARP.
       gfxConfig::EnableFallback(Fallback::USE_D3D11_WARP_COMPOSITOR, message.get());
     } else {
       // There is little to no chance of D3D11 working, so just disable it.
       d3d11.Disable(FeatureStatus::Blacklisted, message.get(),
                     failureId);
     }
@@ -2557,17 +2538,17 @@ gfxWindowsPlatform::InitializeD2DConfig(
 
   d2d1.SetDefaultFromPref(
     gfxPrefs::GetDirect2DDisabledPrefName(),
     false,
     gfxPrefs::GetDirect2DDisabledPrefDefault());
 
   nsCString message;
   nsCString failureId;
-  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D, &message, failureId)) {
+  if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D, &message, failureId)) {
     d2d1.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
   }
 
   if (!d2d1.IsEnabled() && gfxPrefs::Direct2DForceEnabled()) {
     d2d1.UserForceEnable("Force-enabled via user-preference");
   }
 }
 
@@ -2963,17 +2944,17 @@ gfxWindowsPlatform::SupportsApzTouchInpu
 {
   int value = gfxPrefs::TouchEventsEnabled();
   return value == 1 || value == 2;
 }
 
 void
 gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
 {
-  if (gfxPrefs::LayersPreferOpenGL()) {
+  if (gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING) && gfxPrefs::LayersPreferOpenGL()) {
     aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
   }
 
   if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && gfxPrefs::LayersPreferD3D9()) {
     aBackends.AppendElement(LayersBackend::LAYERS_D3D9);
   }
 
   if (mD3D11Device) {
--- a/ipc/glue/TaskFactory.h
+++ b/ipc/glue/TaskFactory.h
@@ -57,40 +57,41 @@ public:
       new TaskWrapper(this, mozilla::Forward<Args>(args)...);
     return task.forget();
   }
 
   template <class Method>
   inline already_AddRefed<Runnable> NewRunnableMethod(Method method) {
     typedef TaskWrapper<RunnableMethod<Method, Tuple0> > TaskWrapper;
 
-    RefPtr<TaskWrapper> task = new TaskWrapper(this);
-    task->Init(object_, method, base::MakeTuple());
+    RefPtr<TaskWrapper> task = new TaskWrapper(this, object_, method,
+                                               base::MakeTuple());
+
     return task.forget();
   }
 
   template <class Method, class A>
   inline already_AddRefed<Runnable> NewRunnableMethod(Method method, const A& a) {
     typedef TaskWrapper<RunnableMethod<Method, Tuple1<A> > > TaskWrapper;
 
-    RefPtr<TaskWrapper> task = new TaskWrapper(this);
-    task->Init(object_, method, base::MakeTuple(a));
+    RefPtr<TaskWrapper> task = new TaskWrapper(this, object_, method,
+                                               base::MakeTuple(a));
+
     return task.forget();
   }
 
 protected:
   template <class Method, class Params>
   class RunnableMethod : public Runnable {
    public:
-    RunnableMethod() { }
+    RunnableMethod(T* obj, Method meth, const Params& params)
+      : obj_(obj)
+      , meth_(meth)
+      , params_(params) {
 
-    void Init(T* obj, Method meth, const Params& params) {
-      obj_ = obj;
-      meth_ = meth;
-      params_ = params;
     }
 
     NS_IMETHOD Run() override {
       DispatchToMethod(obj_, meth_, params_);
       return NS_OK;
     }
 
    private:
--- a/layout/base/crashtests/695861.html
+++ b/layout/base/crashtests/695861.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <html>
 <body onload="document.documentElement.offsetHeight; document.getElementById('s').style.textTransform='uppercase'; document.documentElement.offsetHeight; ">
 
-<div style="white-space: pre-wrap; -moz-column-count: 2;"><span id="s" style="unicode-bidi: -moz-isolate;">
+<div style="white-space: pre-wrap; -moz-column-count: 2;"><span id="s" style="unicode-bidi: isolate;">
  <div style="direction: rtl;"></div></span></div>
 
 </body>
 </html>
--- a/layout/base/crashtests/701504.html
+++ b/layout/base/crashtests/701504.html
@@ -12,13 +12,13 @@ function boom()
 
   document.documentElement.offsetHeight;
 }
 
 </script>
 </head>
 <body onload="boom();">
 
-<div style="-moz-column-count: 2;"><span style="unicode-bidi: -moz-isolate;" id="x"><span style="direction: rtl;"></span> <span style="unicode-bidi: -moz-isolate; white-space: pre;">
+<div style="-moz-column-count: 2;"><span style="unicode-bidi: isolate;" id="x"><span style="direction: rtl;"></span> <span style="unicode-bidi: isolate; white-space: pre;">
 x</span></span></div>
 
 </body>
 </html>
--- a/layout/generic/crashtests/765409.html
+++ b/layout/generic/crashtests/765409.html
@@ -15,11 +15,11 @@ window.addEventListener("load", function
    v.style.width = "280px";
    v.style.height = "10px";
    setTimeout(function(){ document.documentElement.offsetHeight; document.documentElement.removeAttribute("class"); },0);
 }, false);
 
 </script>
 
 <body>
-<div><span style="unicode-bidi: -moz-isolate;"><span style="display: inline-block; float: right;" id="v"></span>D E<span style="unicode-bidi: -moz-isolate;"><span><span> &#x062a;</span></span></span></span></div>
+<div><span style="unicode-bidi: isolate;"><span style="display: inline-block; float: right;" id="v"></span>D E<span style="unicode-bidi: isolate;"><span><span> &#x062a;</span></span></span></span></div>
 </body>
 </html>
--- a/layout/reftests/bidi/1231175-1.html
+++ b/layout/reftests/bidi/1231175-1.html
@@ -5,13 +5,13 @@ div { width: 200px; border: 1px solid bl
 span { direction: rtl; color: red; }
 </style>
 <body>
 <p>The number in the red text should read "18" in all cases.
 <div>
 <ol dir=rtl>
 <li><span style="unicode-bidi: normal">18 ديسمبر</span></li>
 <li><span style="unicode-bidi: embed">18 ديسمبر</span></li>
-<li><span style="unicode-bidi: -moz-isolate; unicode-bidi: isolate">18 ديسمبر</span></li>
-<li><span style="unicode-bidi: -moz-plaintext; unicode-bidi: plaintext">18 ديسمبر</span></li>
+<li><span style="unicode-bidi: isolate">18 ديسمبر</span></li>
+<li><span style="unicode-bidi: plaintext">18 ديسمبر</span></li>
 <li><span>&#x202B;18 ديسمبر&#x202C;</span></li>
 <li><span>&#x2067;18 ديسمبر&#x2069;</span></li>
 <li><span>&#x2068;18 ديسمبر&#x2069;</span></li>
--- a/layout/reftests/bidi/613149-1b.html
+++ b/layout/reftests/bidi/613149-1b.html
@@ -1,17 +1,17 @@
 <!DOCTYPE html>
 <html>
  <head>
   <meta charset="UTF-8">
   <title>Bidi isolation - css</title>
   <style type="text/css">
    body { font-family: monospace; }
-   span { unicode-bidi: -moz-isolate; }
-   span.override { unicode-bidi: -moz-isolate-override; }
+   span { unicode-bidi: isolate; }
+   span.override { unicode-bidi: isolate-override; }
   </style>
  </head>
  <body>
   <p><span>פיצה זהב 24 קאראט</span> - 3 reviews</p>
   <p>מסעדה ראשונה: <span dir="ltr">Joe's פלאפל Bar</span> - 5 תגובות</p>
   <p>מסעדה ראשונה: <span class="override" dir="rtl">raB פלאפל s'eoJ</span> - 5 תגובות</p>
   <p dir="rtl" align="left">תשתמש ב-css (<span dir="ltr">position: relative</span>).</p>
   <p>documents &gt; <span dir="rtl">הרומן הראשון שלי</span> &gt; <span dir="rtl">פרק 1</span></p>
--- a/layout/reftests/bidi/746987-1.html
+++ b/layout/reftests/bidi/746987-1.html
@@ -1,16 +1,14 @@
 <!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8">
     <style>
       .plaintext {
-        unicode-bidi: -moz-plaintext;
-        unicode-bidi: -webkit-plaintext;
         unicode-bidi: plaintext;
       }
     </style>
     <title>unicode-bidi:plaintext on inline</title>
   </head>
   <body>
     <div>[<span class="plaintext">:-) &#x05d0;</span>]: 100</div>
   </body>
--- a/layout/reftests/bidi/746987-2.html
+++ b/layout/reftests/bidi/746987-2.html
@@ -9,18 +9,16 @@
       }
       .test {
         border: medium solid gray;
         padding: 10px;
         width: 400px;
         margin: 20px;
       }
       .plaintext {
-        unicode-bidi: -moz-plaintext;
-        unicode-bidi: -webkit-plaintext;
         unicode-bidi: plaintext;
       }
     </style>
     <title>unicode-bidi:plaintext on inline with paragraph breaks</title>
   </head>
   <body>
     <div class="test">
       <span class="plaintext">a-><br/>&#x05D0;-><br/>a-><br/>&#x05D0;-></span>
--- a/layout/reftests/bidi/746987-3.html
+++ b/layout/reftests/bidi/746987-3.html
@@ -9,23 +9,19 @@
       }
       .test {
         border: medium solid gray;
         padding: 10px;
         width: 400px;
         margin: 20px;
       }
       .plaintext {
-        unicode-bidi: -moz-plaintext;
-        unicode-bidi: -webkit-plaintext;
         unicode-bidi: plaintext;
       }
       .isolate {
-        unicode-bidi: -moz-isolate;
-        unicode-bidi: -webkit-isolate;
         unicode-bidi: isolate;
       }
     </style>
     <title>unicode-bidi:plaintext does not apply to embedded unicode-bidi:isolate</title>
   </head>
   <body>
     <div class="test">
       <span class="plaintext"><span class="isolate">&#x05D0;-></span>=></span>
--- a/layout/reftests/bidi/746987-4.html
+++ b/layout/reftests/bidi/746987-4.html
@@ -9,18 +9,16 @@
       }
       .test {
         border: medium solid gray;
         padding: 10px;
         width: 400px;
         margin: 20px;
       }
       .plaintext {
-        unicode-bidi: -moz-plaintext;
-        unicode-bidi: -webkit-plaintext;
         unicode-bidi: plaintext;
       }
     </style>
     <title>unicode-bidi:plaintext does not apply to embedded display:block</title>
   </head>
   <body>
     <div class="test">
       <div class="plaintext">
--- a/layout/reftests/bidi/869833-1.xul
+++ b/layout/reftests/bidi/869833-1.xul
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml-stylesheet type="text/css" href="data:text/css,
-treechildren::-moz-tree-cell, label { unicode-bidi: -moz-plaintext; }
+treechildren::-moz-tree-cell, label { unicode-bidi: plaintext; }
 tree { height: 100px; }
 "?>
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <tree>
     <treecols>
       <treecol flex="1"/>
     </treecols>
     <treechildren>
--- a/layout/reftests/bidi/brackets-3b-ltr-ref.html
+++ b/layout/reftests/bidi/brackets-3b-ltr-ref.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 
 <style>
 body { font: 32px monospace; }
 div { text-align: center; }
-span { unicode-bidi: -moz-isolate; unicode-bidi: isolate; }
+span { unicode-bidi: isolate; }
 </style>
 
 <body>
 
 <!--
   http://unicode.org/reports/tr9/#N0, Example 3, LTR and RTL exchanged:
     arabic BOOK(S)
 -->
--- a/layout/reftests/bidi/brackets-3b-rtl-ref.html
+++ b/layout/reftests/bidi/brackets-3b-rtl-ref.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 
 <style>
 body { font: 32px monospace; }
 div { text-align: center; }
-span { unicode-bidi: -moz-isolate; unicode-bidi: isolate; }
+span { unicode-bidi: isolate; }
 </style>
 
 <body>
 
 <!--
   http://unicode.org/reports/tr9/#N0, Example 3, LTR and RTL exchanged:
     arabic BOOK(S)
 -->
--- a/layout/reftests/bidi/dirAuto/889742-1.html
+++ b/layout/reftests/bidi/dirAuto/889742-1.html
@@ -1,17 +1,15 @@
 <!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8">
     <title>Auto dir and alignment</title>
     <style type="text/css">
       p.plaintext {
-        unicode-bidi: -moz-plaintext;
-        unicode-bidi: -webkit-plaintext;
         unicode-bidi: plaintext;
       }
     </style>
   </head>
   <body>
     <h1>Auto dir and alignment</h1>
     <p>Every line below should read "<span style="unicode-bidi: bidi-override"
 >!world םולש</span>" and should be aligned to the right</p>
--- a/layout/reftests/bidi/unicode-bidi-isolate-aharon.html
+++ b/layout/reftests/bidi/unicode-bidi-isolate-aharon.html
@@ -1,15 +1,13 @@
 <!DOCTYPE html>
 <html><head>
 <title>Test cases for unicode-bidi:isolate</title>
 <style>
   .isolate {
-    unicode-bidi: -webkit-isolate;
-    unicode-bidi: -moz-isolate;
     unicode-bidi: isolate;
   }
 </style>
 </head><body>
 opposite-to-base isolate followed by number.
 <div>
   <div class="test">
     <span class="isolate">&#x05D0;</span> (3 reviews)
--- a/layout/reftests/bidi/unicode-bidi-isolate-basic.html
+++ b/layout/reftests/bidi/unicode-bidi-isolate-basic.html
@@ -6,17 +6,17 @@
 <style>
 .resultsDiv {
     -moz-column-width: 3em;
     -webkit-column-width: 3em;
     -moz-column-gap: 5em;
     -webkit-column-gap: 5em;
     text-align: left;
 }
-.enclosed { unicode-bidi: -moz-isolate; }
+.enclosed { unicode-bidi: isolate; }
 </style>
 </head>
 <body onload="buildTable()">
 <div id="resultsContainer" style="position: relative">
 <div id="elem" class="resultsDiv"></div>
 </div>
 </body>
 </html>
--- a/layout/reftests/bidi/unicode-bidi-plaintext-textarea-2.html
+++ b/layout/reftests/bidi/unicode-bidi-plaintext-textarea-2.html
@@ -1,16 +1,14 @@
 <!DOCTYPE html>
 <html><head>
 <title>unicode-bidi:plaintext</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <style>
   .plaintext {
-    unicode-bidi:-webkit-plaintext;
-    unicode-bidi:-moz-plaintext;
     unicode-bidi:plaintext;
   }
   textarea { text-align: left; resize: none; }
 </style>
 </head><body>
 <div>
 The exclamation mark should be on the left side of the first line
 and on the right side of the second line.
--- a/layout/reftests/bidi/unicode-bidi-plaintext-textarea-3.html
+++ b/layout/reftests/bidi/unicode-bidi-plaintext-textarea-3.html
@@ -1,16 +1,14 @@
 <!DOCTYPE html>
 <html><head>
 <title>unicode-bidi:plaintext</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <style>
   .plaintext {
-    unicode-bidi:-webkit-plaintext;
-    unicode-bidi:-moz-plaintext;
     unicode-bidi:plaintext;
   }
   textarea { text-align: left; resize: none; }
 </style>
 </head><body>
 <div>
 The exclamation mark should be on the left side of the first line
 and on the right side of the second line.
--- a/layout/reftests/bidi/unicode-bidi-plaintext-textarea-4.html
+++ b/layout/reftests/bidi/unicode-bidi-plaintext-textarea-4.html
@@ -1,16 +1,14 @@
 <!DOCTYPE html>
 <html><head>
 <title>unicode-bidi:plaintext</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <style>
   .plaintext {
-    unicode-bidi:-webkit-plaintext;
-    unicode-bidi:-moz-plaintext;
     unicode-bidi:plaintext;
   }
   textarea { text-align: left; resize: none; }
 </style>
 </head><body>
 <div>
 The exclamation mark should be on the left side of the first line
 and on the right side of the second line.
--- a/layout/reftests/bidi/unicode-bidi-plaintext.html
+++ b/layout/reftests/bidi/unicode-bidi-plaintext.html
@@ -2,17 +2,17 @@
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <style> 
 div, pre { text-align: left; }
 </style>
 </head>
 <body>
-<div style="unicode-bidi: -webkit-plaintext; unicode-bidi: -moz-plaintext; unicode-bidi: plaintext;">
+<div style="unicode-bidi: plaintext;">
 !hello.
 <br>
 !שלום.
 <br>
 hello, לוי!
 <br>
 שלום, WebKit!
 </div>
--- a/layout/reftests/css-ruby/common.css
+++ b/layout/reftests/css-ruby/common.css
@@ -1,15 +1,15 @@
 @font-face {
   font-family: Ahem;
   src: url(../fonts/Ahem.ttf);
 }
 rbc {
   display: ruby-base-container;
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 [pseudo] {
   font-size: inherit;
   line-height: inherit;
 }
 [pseudo] > rt {
   font-size: 50%;
 }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/as-image/defer-unsupported-1-helper.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"
+     viewBox="0 0 50 50" preserveAspectRatio="xMaxYMax">
+
+  <rect width="100" height="100" fill="lime"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/as-image/defer-unsupported-1-ref.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <rect width="100" height="100" fill="blue"/>
+  <image xlink:href="defer-unsupported-1-helper.svg" width="200" height="100"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/as-image/defer-unsupported-1.svg
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <rect width="100" height="100" fill="blue"/>
+  <image xlink:href="defer-unsupported-1-helper.svg" width="200" height="100"
+         preserveAspectRatio="defer xMinYMin"/>
+</svg>
--- a/layout/reftests/svg/as-image/reftest.list
+++ b/layout/reftests/svg/as-image/reftest.list
@@ -235,8 +235,11 @@ skip-if(B2G||Mulet) fuzzy(2,1) == svg-bo
 != nonuniform-scale-2d.html?0.3&1.0  nonuniform-scale-2d.html?0.3&0.3
 != nonuniform-scale-2d.html?0.3&1.0  nonuniform-scale-2d.html?1.0&1.0
 != nonuniform-scale-2d.html?1.0&0.3  nonuniform-scale-2d.html?0.3&0.3
 != nonuniform-scale-2d.html?1.0&0.3  nonuniform-scale-2d.html?1.0&1.0
 != nonuniform-scale-3d.html?0.3&1.0&0.3  nonuniform-scale-3d.html?0.3&0.3&0.3
 != nonuniform-scale-3d.html?0.3&1.0&0.3  nonuniform-scale-3d.html?1.0&1.0&1.0
 != nonuniform-scale-3d.html?1.0&0.3&0.3  nonuniform-scale-3d.html?0.3&0.3&0.3
 != nonuniform-scale-3d.html?1.0&0.3&0.3  nonuniform-scale-3d.html?1.0&1.0&1.0
+
+# Test for preserveAspectRatio with no-longer-supported "defer" keyword
+== defer-unsupported-1.svg  defer-unsupported-1-ref.svg
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -330,16 +330,17 @@ CSS_KEY(inline-grid, inline_grid)
 CSS_KEY(inline-start, inline_start)
 CSS_KEY(inline-table, inline_table)
 CSS_KEY(inset, inset)
 CSS_KEY(inside, inside)
 // CSS_KEY(inter-character, inter_character) // TODO see bug 1055672
 CSS_KEY(interpolatematrix, interpolatematrix)
 CSS_KEY(intersect, intersect)
 CSS_KEY(isolate, isolate)
+CSS_KEY(isolate-override, isolate_override)
 CSS_KEY(invert, invert)
 CSS_KEY(italic, italic)
 CSS_KEY(japanese-formal, japanese_formal)
 CSS_KEY(japanese-informal, japanese_informal)
 CSS_KEY(jis78, jis78)
 CSS_KEY(jis83, jis83)
 CSS_KEY(jis90, jis90)
 CSS_KEY(jis04, jis04)
@@ -434,16 +435,17 @@ CSS_KEY(padding-box, padding_box)
 CSS_KEY(painted, painted)
 CSS_KEY(pan-x, pan_x)
 CSS_KEY(pan-y, pan_y)
 CSS_KEY(paused, paused)
 CSS_KEY(pc, pc)
 CSS_KEY(perspective, perspective)
 CSS_KEY(petite-caps, petite_caps)
 CSS_KEY(physical, physical)
+CSS_KEY(plaintext, plaintext)
 CSS_KEY(pointer, pointer)
 CSS_KEY(polygon, polygon)
 CSS_KEY(portrait, portrait)
 CSS_KEY(pre, pre)
 CSS_KEY(pre-wrap, pre_wrap)
 CSS_KEY(pre-line, pre_line)
 CSS_KEY(preserve-3d, preserve_3d)
 CSS_KEY(progress, progress)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -2105,16 +2105,19 @@ const KTableEntry nsCSSProps::kTransitio
   { eCSSKeyword_step_end, NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kUnicodeBidiKTable[] = {
   { eCSSKeyword_normal, NS_STYLE_UNICODE_BIDI_NORMAL },
   { eCSSKeyword_embed, NS_STYLE_UNICODE_BIDI_EMBED },
   { eCSSKeyword_bidi_override, NS_STYLE_UNICODE_BIDI_BIDI_OVERRIDE },
+  { eCSSKeyword_isolate, NS_STYLE_UNICODE_BIDI_ISOLATE },
+  { eCSSKeyword_isolate_override, NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE },
+  { eCSSKeyword_plaintext, NS_STYLE_UNICODE_BIDI_PLAINTEXT },
   { eCSSKeyword__moz_isolate, NS_STYLE_UNICODE_BIDI_ISOLATE },
   { eCSSKeyword__moz_isolate_override, NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE },
   { eCSSKeyword__moz_plaintext, NS_STYLE_UNICODE_BIDI_PLAINTEXT },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kUserFocusKTable[] = {
   { eCSSKeyword_none,           NS_STYLE_USER_FOCUS_NONE },
--- a/layout/style/res/html.css
+++ b/layout/style/res/html.css
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 @namespace url(http://www.w3.org/1999/xhtml); /* set default namespace to HTML */
 @namespace xul url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
 
 /* bidi */
 
 [dir] {
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 [dir="rtl"] {
   direction: rtl;
 }
 [dir="ltr"] {
   direction: ltr;
 }
 
@@ -78,29 +78,29 @@ table,
 tbody,
 td,
 tfoot,
 th,
 thead,
 tr,
 ul,
 xmp {
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 
 bdi, output {
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 bdo, bdo[dir] {
   unicode-bidi: bidi-override;
 }
 bdo[dir="auto"] {
-  unicode-bidi: -moz-isolate-override;
+  unicode-bidi: isolate-override;
 }
-textarea[dir="auto"], pre[dir="auto"] { unicode-bidi: -moz-plaintext; }
+textarea[dir="auto"], pre[dir="auto"] { unicode-bidi: plaintext; }
 
 /* blocks */
 
 article,
 aside,
 details,
 div,
 dt,
@@ -639,17 +639,17 @@ hr[size="1"] {
 }
 
 img:-moz-broken::before, input:-moz-broken::before,
 img:-moz-user-disabled::before, input:-moz-user-disabled::before,
 img:-moz-loading::before, input:-moz-loading::before,
 applet:-moz-empty-except-children-with-localname(param):-moz-broken::before,
 applet:-moz-empty-except-children-with-localname(param):-moz-user-disabled::before {
   content: -moz-alt-content !important;
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 
 :-moz-any(object,applet):-moz-any(:-moz-broken,:-moz-user-disabled) > *|* {
   /*
     Inherit in the object's alignment so that if we aren't aligned explicitly
     we'll end up in the right place vertically.  See bug 36997.  Note that this
     is not !important because we _might_ be aligned explicitly.
   */
@@ -850,10 +850,10 @@ rtc:lang(zh), rt:lang(zh) {
 rtc:lang(zh-TW), rt:lang(zh-TW) {
   font-size: 30%; /* bopomofo */
   -moz-min-font-size-ratio: 30%;
 }
 rtc > rt {
   font-size: inherit;
 }
 ruby, rb, rt, rtc {
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
--- a/layout/style/res/ua.css
+++ b/layout/style/res/ua.css
@@ -71,33 +71,33 @@
 *|*::-moz-table-cell {
   display: table-cell !important;
   white-space: inherit;
 }
 
 /* Ruby */
 *|*::-moz-ruby {
   display: ruby;
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 *|*::-moz-ruby-base {
   display: ruby-base;
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 *|*::-moz-ruby-text {
   display: ruby-text;
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 *|*::-moz-ruby-base-container {
   display: ruby-base-container;
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 *|*::-moz-ruby-text-container {
   display: ruby-text-container;
-  unicode-bidi: -moz-isolate;
+  unicode-bidi: isolate;
 }
 
 /* Lists */
 
 *|*::-moz-list-bullet, *|*::-moz-list-number {
   display: inline;
   vertical-align: baseline;
   font-variant-numeric: tabular-nums;
--- a/layout/style/res/viewsource.css
+++ b/layout/style/res/viewsource.css
@@ -86,16 +86,16 @@ span[id]:before {
 .highlight .markupdeclaration {
  color: steelblue;
  font-style: italic;
 }
 span:not(.error), a:not(.error) {
  unicode-bidi: embed;
 }
 span[id] {
- unicode-bidi: -moz-isolate;
+ unicode-bidi: isolate;
 }
 .highlight .error,
 .highlight .error > :-moz-any(.start-tag, .end-tag, .comment, .cdata, .doctype,
                               .pi, .entity, .attribute-name, .attribute-value) {
   color: red;
   font-weight: bold;
 }
--- a/layout/style/test/file_animations_effect_timing_enddelay.html
+++ b/layout/style/test/file_animations_effect_timing_enddelay.html
@@ -63,36 +63,36 @@ addAsyncAnimTest(function *() {
   var animation = div.animate(
     [ { transform: 'translate(0px)' }, { transform: 'translate(100px)' } ],
     { duration: 1000, endDelay: -500, fill: 'none' });
   yield waitForPaints();
 
   advance_clock(400);
   yield waitForPaints();
   omta_is(div, "transform", { tx: 40 }, RunningOn.Compositor,
-          "Animation is updated on compositor" +
+          "Animation is updated on compositor " +
           "duration 1000, endDelay -500, fill none, current time 400");
 
   advance_clock(100);
   yield waitForPaints();
   omta_is(div, "transform", { tx: 0 }, RunningOn.MainThread,
-          "Animation is updated on main thread" +
+          "Animation is updated on main thread " +
           "duration 1000, endDelay -500, fill none, current time 500");
 
   advance_clock(400);
   yield waitForPaints();
   omta_is(div, "transform", { tx: 0 }, RunningOn.MainThread,
-          "Animation is updated on main thread" +
-          "duration 1000, endDelay -500, fill forwards, current time 900");
+          "Animation is updated on main thread " +
+          "duration 1000, endDelay -500, fill none, current time 900");
 
   advance_clock(100);
   yield waitForPaints();
   omta_is(div, "transform", { tx: 0 }, RunningOn.MainThread,
-          "Animation is updated on main thread" +
-          "duration 1000, endDelay -500, fill forwards, current time 1000");
+          "Animation is updated on main thread " +
+          "duration 1000, endDelay -500, fill none, current time 1000");
 
   done_div();
 });
 
 addAsyncAnimTest(function *() {
   var [ div ] = new_div("");
   var animation = div.animate(
     [ { transform: 'translate(0px)' }, { transform: 'translate(100px)' } ],
@@ -112,35 +112,35 @@ addAsyncAnimTest(function *() {
   var animation = div.animate(
     [ { transform: 'translate(0px)' }, { transform: 'translate(100px)' } ],
     { duration: 1000, endDelay: -500, fill: 'forwards' });
   yield waitForPaints();
 
   advance_clock(400);
   yield waitForPaints();
   omta_is(div, "transform", { tx: 40 }, RunningOn.Compositor,
-          "Animation is updated on compositor" +
+          "Animation is updated on compositor " +
           "duration 1000, endDelay -500, fill forwards, current time 400");
 
   advance_clock(100);
   yield waitForPaints();
-  omta_is(div, "transform", { tx: 100 }, RunningOn.MainThread,
-          "Animation is updated on main thread" +
+  omta_is(div, "transform", { tx: 50 }, RunningOn.MainThread,
+          "Animation is updated on main thread " +
           "duration 1000, endDelay -500, fill forwards, current time 500");
 
   advance_clock(400);
   yield waitForPaints();
-  omta_is(div, "transform", { tx: 100 }, RunningOn.MainThread,
-          "Animation is updated on main thread" +
+  omta_is(div, "transform", { tx: 50 }, RunningOn.MainThread,
+          "Animation is updated on main thread " +
           "duration 1000, endDelay -500, fill forwards, current time 900");
 
   advance_clock(100);
   yield waitForPaints();
-  omta_is(div, "transform", { tx: 100 }, RunningOn.MainThread,
-          "Animation is updated on main thread" +
+  omta_is(div, "transform", { tx: 50 }, RunningOn.MainThread,
+          "Animation is updated on main thread " +
           "duration 1000, endDelay -500, fill forwards, current time 1000");
 
   done_div();
 });
 
 </script>
 </body>
 </html>
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -3898,17 +3898,17 @@ var gCSSProperties = {
     other_values: [ "cubic-bezier(0.25, 0.1, 0.25, 1.0)", "linear", "ease-in", "ease-out", "ease-in-out", "linear, ease-in, cubic-bezier(0.1, 0.2, 0.8, 0.9)", "cubic-bezier(0.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.25, 1.5, 0.75, -0.5)", "step-start", "step-end", "steps(1)", "steps(2, start)", "steps(386)", "steps(3, end)" ],
     invalid_values: [ "none", "auto", "cubic-bezier(0.25, 0.1, 0.25)", "cubic-bezier(0.25, 0.1, 0.25, 0.25, 1.0)", "cubic-bezier(-0.5, 0.5, 0.5, 0.5)", "cubic-bezier(1.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.5, 0.5, -0.5, 0.5)", "cubic-bezier(0.5, 0.5, 1.5, 0.5)", "steps(2, step-end)", "steps(0)", "steps(-2)", "steps(0, step-end, 1)" ]
   },
   "unicode-bidi": {
     domProp: "unicodeBidi",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "normal" ],
-    other_values: [ "embed", "bidi-override", "-moz-isolate", "-moz-plaintext", "-moz-isolate-override" ],
+    other_values: [ "embed", "bidi-override", "isolate", "plaintext", "isolate-override", "-moz-isolate", "-moz-plaintext", "-moz-isolate-override" ],
     invalid_values: [ "auto", "none" ]
   },
   "vertical-align": {
     domProp: "verticalAlign",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "baseline" ],
     other_values: [ "sub", "super", "top", "text-top", "middle", "bottom", "text-bottom", "-moz-middle-with-baseline", "15%", "3px", "0.2em", "-5px", "-3%",
--- a/layout/style/test/test_default_bidi_css.html
+++ b/layout/style/test/test_default_bidi_css.html
@@ -20,57 +20,57 @@ function styleOf(name, attributes) {
     for (var name in attributes) {
         var value = attributes[name];
         element.setAttribute(name, value);
     }
     return getComputedStyle(element);
 }
 
 var tests = [
-    ['div', {}, 'ltr', '-moz-isolate'],
-    ['div', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
-    ['div', {'dir': 'rtl'}, 'rtl', '-moz-isolate'],
-    ['div', {'dir': 'auto'}, 'ltr', '-moz-isolate'],
-    ['div', {'dir': ''}, 'ltr', '-moz-isolate'],
+    ['div', {}, 'ltr', 'isolate'],
+    ['div', {'dir': 'ltr'}, 'ltr', 'isolate'],
+    ['div', {'dir': 'rtl'}, 'rtl', 'isolate'],
+    ['div', {'dir': 'auto'}, 'ltr', 'isolate'],
+    ['div', {'dir': ''}, 'ltr', 'isolate'],
 
     ['span', {}, 'ltr', 'normal'],
-    ['span', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
-    ['span', {'dir': 'rtl'}, 'rtl', '-moz-isolate'],
-    ['span', {'dir': 'auto'}, 'ltr', '-moz-isolate'],
-    ['span', {'dir': ''}, 'ltr', '-moz-isolate'],
+    ['span', {'dir': 'ltr'}, 'ltr', 'isolate'],
+    ['span', {'dir': 'rtl'}, 'rtl', 'isolate'],
+    ['span', {'dir': 'auto'}, 'ltr', 'isolate'],
+    ['span', {'dir': ''}, 'ltr', 'isolate'],
 
-    ['bdi', {}, 'ltr', '-moz-isolate'],
-    ['bdi', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
-    ['bdi', {'dir': 'rtl'}, 'rtl', '-moz-isolate'],
-    ['bdi', {'dir': 'auto'}, 'ltr', '-moz-isolate'],
-    ['bdi', {'dir': ''}, 'ltr', '-moz-isolate'],
+    ['bdi', {}, 'ltr', 'isolate'],
+    ['bdi', {'dir': 'ltr'}, 'ltr', 'isolate'],
+    ['bdi', {'dir': 'rtl'}, 'rtl', 'isolate'],
+    ['bdi', {'dir': 'auto'}, 'ltr', 'isolate'],
+    ['bdi', {'dir': ''}, 'ltr', 'isolate'],
 
-    ['output', {}, 'ltr', '-moz-isolate'],
-    ['output', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
-    ['output', {'dir': 'rtl'}, 'rtl', '-moz-isolate'],
-    ['output', {'dir': 'auto'}, 'ltr', '-moz-isolate'],
-    ['output', {'dir': ''}, 'ltr', '-moz-isolate'],
+    ['output', {}, 'ltr', 'isolate'],
+    ['output', {'dir': 'ltr'}, 'ltr', 'isolate'],
+    ['output', {'dir': 'rtl'}, 'rtl', 'isolate'],
+    ['output', {'dir': 'auto'}, 'ltr', 'isolate'],
+    ['output', {'dir': ''}, 'ltr', 'isolate'],
 
     ['bdo', {}, 'ltr', 'bidi-override'],
     ['bdo', {'dir': 'ltr'}, 'ltr', 'bidi-override'],
     ['bdo', {'dir': 'rtl'}, 'rtl', 'bidi-override'],
-    ['bdo', {'dir': 'auto'}, 'ltr', '-moz-isolate-override'],
+    ['bdo', {'dir': 'auto'}, 'ltr', 'isolate-override'],
     ['bdo', {'dir': ''}, 'ltr', 'bidi-override'],
 
     ['textarea', {}, 'ltr', 'normal'],
-    ['textarea', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
-    ['textarea', {'dir': 'rtl'}, 'rtl', '-moz-isolate'],
-    ['textarea', {'dir': 'auto'}, 'ltr', '-moz-plaintext'],
-    ['textarea', {'dir': ''}, 'ltr', '-moz-isolate'],
+    ['textarea', {'dir': 'ltr'}, 'ltr', 'isolate'],
+    ['textarea', {'dir': 'rtl'}, 'rtl', 'isolate'],
+    ['textarea', {'dir': 'auto'}, 'ltr', 'plaintext'],
+    ['textarea', {'dir': ''}, 'ltr', 'isolate'],
 
-    ['pre', {}, 'ltr', '-moz-isolate'],
-    ['pre', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
-    ['pre', {'dir': 'rtl'}, 'rtl', '-moz-isolate'],
-    ['pre', {'dir': 'auto'}, 'ltr', '-moz-plaintext'],
-    ['pre', {'dir': ''}, 'ltr', '-moz-isolate'],
+    ['pre', {}, 'ltr', 'isolate'],
+    ['pre', {'dir': 'ltr'}, 'ltr', 'isolate'],
+    ['pre', {'dir': 'rtl'}, 'rtl', 'isolate'],
+    ['pre', {'dir': 'auto'}, 'ltr', 'plaintext'],
+    ['pre', {'dir': ''}, 'ltr', 'isolate'],
 ].forEach(function (test) {
     var style = styleOf(test[0], test[1]);
     is(style.direction, test[2], "default value for direction");
     is(style.unicodeBidi, test[3], "default value for unicode-bidi");
 });
 
 
 </script>
--- a/media/libstagefright/binding/MP4Metadata.cpp
+++ b/media/libstagefright/binding/MP4Metadata.cpp
@@ -9,27 +9,28 @@
 #include "media/stagefright/MetaData.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Logging.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/UniquePtr.h"
-#include "OpusDecoder.h"
 #include "VideoUtils.h"
 #include "mp4_demuxer/MoofParser.h"
 #include "mp4_demuxer/MP4Metadata.h"
 #include "mp4_demuxer/Stream.h"
 
 #include <limits>
 #include <stdint.h>
 #include <vector>
 
 #ifdef MOZ_RUST_MP4PARSE
+// OpusDecoder header is really needed only by MP4 in rust
+#include "OpusDecoder.h"
 #include "mp4parse.h"
 
 struct FreeMP4Parser { void operator()(mp4parse_parser* aPtr) { mp4parse_free(aPtr); } };
 #endif
 
 using namespace stagefright;
 
 namespace mp4_demuxer
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -461,21 +461,16 @@ WebrtcVideoConduit::Init()
 
   CSFLogError(logTag, "%s Initialization Done", __FUNCTION__);
   return kMediaConduitNoError;
 }
 
 void
 WebrtcVideoConduit::Destroy()
 {
-  for(std::vector<VideoCodecConfig*>::size_type i=0;i < mRecvCodecList.size();i++)
-  {
-    delete mRecvCodecList[i];
-  }
-
   // The first one of a pair to be deleted shuts down media for both
   //Deal with External Capturer
   if(mPtrViECapture)
   {
     mPtrViECapture->DisconnectCaptureDevice(mCapId);
     mPtrViECapture->ReleaseCaptureDevice(mCapId);
     mPtrExtCapture = nullptr;
   }
@@ -883,23 +878,17 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
       // values SetReceiveCodec() cares about are name, type, maxbitrate
       if(mPtrViECodec->SetReceiveCodec(mChannel,video_codec) == -1)
       {
         CSFLogError(logTag, "%s Invalid Receive Codec %d ", __FUNCTION__,
                     mPtrViEBase->LastError());
       } else {
         CSFLogError(logTag, "%s Successfully Set the codec %s", __FUNCTION__,
                     codecConfigList[i]->mName.c_str());
-        if(CopyCodecToDB(codecConfigList[i]))
-        {
-          success = true;
-        } else {
-          CSFLogError(logTag,"%s Unable to update Codec Database", __FUNCTION__);
-          return kMediaConduitUnknownError;
-        }
+        success = true;
       }
     } else {
       //Retrieve pre-populated codec structure for our codec.
       for(int idx=0; idx < mPtrViECodec->NumberOfCodecs(); idx++)
       {
         if(mPtrViECodec->GetCodec(idx, video_codec) == 0)
         {
           payloadName = video_codec.plName;
@@ -908,23 +897,17 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
             CodecConfigToWebRTCCodec(codecConfigList[i], video_codec);
             if(mPtrViECodec->SetReceiveCodec(mChannel,video_codec) == -1)
             {
               CSFLogError(logTag, "%s Invalid Receive Codec %d ", __FUNCTION__,
                           mPtrViEBase->LastError());
             } else {
               CSFLogError(logTag, "%s Successfully Set the codec %s", __FUNCTION__,
                           codecConfigList[i]->mName.c_str());
-              if(CopyCodecToDB(codecConfigList[i]))
-              {
-                success = true;
-              } else {
-                CSFLogError(logTag,"%s Unable to update Codec Database", __FUNCTION__);
-                return kMediaConduitUnknownError;
-              }
+              success = true;
             }
             break; //we found a match
           }
         }
       }//end for codeclist
     }
   }//end for
 
@@ -1044,17 +1027,16 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
   if (condError != kMediaConduitNoError) {
     return condError;
   }
 
   // by now we should be successfully started the reception
   CSFLogDebug(logTag, "REMB enabled for video stream %s",
               (use_remb ? "yes" : "no"));
   mPtrRTP->SetRembStatus(mChannel, use_remb, true);
-  DumpCodecDB();
   return kMediaConduitNoError;
 }
 
 template<typename T>
 T MinIgnoreZero(const T& a, const T& b)
 {
   return std::min(a? a:b, b? b:a);
 }
@@ -1993,116 +1975,41 @@ WebrtcVideoConduit::CodecConfigToWebRTCC
     // webrtc.org expects simulcast streams to be ordered by increasing
     // fidelity, our jsep code does the opposite.
     cinst.simulcastStream[codecInfo->mSimulcastEncodings.size()-i-1] = stream;
   }
 
   cinst.numberOfSimulcastStreams = codecInfo->mSimulcastEncodings.size();
 }
 
-//Copy the codec passed into Conduit's database
-bool
-WebrtcVideoConduit::CopyCodecToDB(const VideoCodecConfig* codecInfo)
-{
-  VideoCodecConfig* cdcConfig = new VideoCodecConfig(*codecInfo);
-  mRecvCodecList.push_back(cdcConfig);
-  return true;
-}
-
-bool
-WebrtcVideoConduit::CheckCodecsForMatch(const VideoCodecConfig* curCodecConfig,
-                                        const VideoCodecConfig* codecInfo) const
-{
-  if(!curCodecConfig)
-  {
-    return false;
-  }
-
-  if(curCodecConfig->mType  == codecInfo->mType &&
-     curCodecConfig->mName.compare(codecInfo->mName) == 0 &&
-     curCodecConfig->mEncodingConstraints == codecInfo->mEncodingConstraints)
-  {
-    return true;
-  }
-
-  return false;
-}
-
-/**
- * Checks if the codec is already in Conduit's database
- */
-bool
-WebrtcVideoConduit::CheckCodecForMatch(const VideoCodecConfig* codecInfo) const
-{
-  //the db should have atleast one codec
-  for(std::vector<VideoCodecConfig*>::size_type i=0;i < mRecvCodecList.size();i++)
-  {
-    if(CheckCodecsForMatch(mRecvCodecList[i],codecInfo))
-    {
-      //match
-      return true;
-    }
-  }
-  //no match or empty local db
-  return false;
-}
-
 /**
  * Perform validation on the codecConfig to be applied
  * Verifies if the codec is already applied.
  */
 MediaConduitErrorCode
 WebrtcVideoConduit::ValidateCodecConfig(const VideoCodecConfig* codecInfo,
                                         bool send)
 {
-  bool codecAppliedAlready = false;
-
   if(!codecInfo)
   {
     CSFLogError(logTag, "%s Null CodecConfig ", __FUNCTION__);
     return kMediaConduitMalformedArgument;
   }
 
   if((codecInfo->mName.empty()) ||
      (codecInfo->mName.length() >= CODEC_PLNAME_SIZE))
   {
     CSFLogError(logTag, "%s Invalid Payload Name Length ", __FUNCTION__);
     return kMediaConduitMalformedArgument;
   }
 
-  //check if we have the same codec already applied
-  if(send)
-  {
-    MutexAutoLock lock(mCodecMutex);
-
-    codecAppliedAlready = CheckCodecsForMatch(mCurSendCodecConfig,codecInfo);
-  } else {
-    codecAppliedAlready = CheckCodecForMatch(codecInfo);
-  }
-
-  if(codecAppliedAlready)
-  {
-    CSFLogDebug(logTag, "%s Codec %s Already Applied  ", __FUNCTION__, codecInfo->mName.c_str());
-  }
   return kMediaConduitNoError;
 }
 
 void
-WebrtcVideoConduit::DumpCodecDB() const
-{
-  for(std::vector<VideoCodecConfig*>::size_type i=0;i<mRecvCodecList.size();i++)
-  {
-    CSFLogDebug(logTag,"Payload Name: %s", mRecvCodecList[i]->mName.c_str());
-    CSFLogDebug(logTag,"Payload Type: %d", mRecvCodecList[i]->mType);
-    CSFLogDebug(logTag,"Payload Max Frame Size: %d", mRecvCodecList[i]->mEncodingConstraints.maxFs);
-    CSFLogDebug(logTag,"Payload Max Frame Rate: %d", mRecvCodecList[i]->mEncodingConstraints.maxFps);
-  }
-}
-
-void
 WebrtcVideoConduit::VideoLatencyUpdate(uint64_t newSample)
 {
   mVideoLatencyAvg = (sRoundingPadding * newSample + sAlphaNum * mVideoLatencyAvg) / sAlphaDen;
 }
 
 uint64_t
 WebrtcVideoConduit::MozVideoLatencyAvg()
 {
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -340,25 +340,16 @@ private:
 
   //Local database of currently applied receive codecs
   typedef std::vector<VideoCodecConfig* > RecvCodecList;
 
   //Function to convert between WebRTC and Conduit codec structures
   void CodecConfigToWebRTCCodec(const VideoCodecConfig* codecInfo,
                                 webrtc::VideoCodec& cinst);
 
-  // Function to copy a codec structure to Conduit's database
-  bool CopyCodecToDB(const VideoCodecConfig* codecInfo);
-
-  // Functions to verify if the codec passed is already in
-  // conduits database
-  bool CheckCodecForMatch(const VideoCodecConfig* codecInfo) const;
-  bool CheckCodecsForMatch(const VideoCodecConfig* curCodecConfig,
-                           const VideoCodecConfig* codecInfo) const;
-
   //Checks the codec to be applied
   MediaConduitErrorCode ValidateCodecConfig(const VideoCodecConfig* codecInfo, bool send);
 
   //Utility function to dump recv codec database
   void DumpCodecDB() const;
 
   // Video Latency Test averaging filter
   void VideoLatencyUpdate(uint64_t new_sample);
@@ -383,17 +374,16 @@ private:
   webrtc::ViEExternalCapture* mPtrExtCapture;
 
   // Engine state we are concerned with.
   mozilla::Atomic<bool> mEngineTransmitting; //If true ==> Transmit Sub-system is up and running
   mozilla::Atomic<bool> mEngineReceiving;    // if true ==> Receive Sus-sysmtem up and running
 
   int mChannel; // Video Channel for this conduit
   int mCapId;   // Capturer for this conduit
-  RecvCodecList    mRecvCodecList;
 
   Mutex mCodecMutex; // protects mCurrSendCodecConfig
   nsAutoPtr<VideoCodecConfig> mCurSendCodecConfig;
   bool mInReconfig;
 
   unsigned short mLastWidth;
   unsigned short mLastHeight;
   unsigned short mSendingWidth;
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -1300,16 +1300,18 @@ BookmarksStore.prototype = {
         }
       cb();
     });
     cb.wait();
   }
 };
 
 function BookmarksTracker(name, engine) {
+  this._batchDepth = 0;
+  this._batchSawScoreIncrement = false;
   Tracker.call(this, name, engine);
 
   Svc.Obs.add("places-shutdown", this);
 }
 BookmarksTracker.prototype = {
   __proto__: Tracker.prototype,
 
   startTracking: function() {
@@ -1363,19 +1365,24 @@ BookmarksTracker.prototype = {
    *        GUID of the bookmark to upload.
    */
   _add: function BMT__add(itemId, guid) {
     guid = BookmarkSpecialIds.specialGUIDForId(itemId) || guid;
     if (this.addChangedID(guid))
       this._upScore();
   },
 
-  /* Every add/remove/change will trigger a sync for MULTI_DEVICE. */
+  /* Every add/remove/change will trigger a sync for MULTI_DEVICE (except in
+     a batch operation, where we do it at the end of the batch) */
   _upScore: function BMT__upScore() {
-    this.score += SCORE_INCREMENT_XLARGE;
+    if (this._batchDepth == 0) {
+      this.score += SCORE_INCREMENT_XLARGE;
+    } else {
+      this._batchSawScoreIncrement = true;
+    }
   },
 
   /**
    * Determine if a change should be ignored.
    *
    * @param itemId
    *        Item under consideration to ignore
    * @param folder (optional)
@@ -1518,12 +1525,18 @@ BookmarksTracker.prototype = {
       this._add(itemId, guid);
       this._add(newParent, newParentGuid);
     }
 
     // Remove any position annotations now that the user moved the item
     PlacesUtils.annotations.removeItemAnnotation(itemId, BookmarkAnnos.PARENT_ANNO);
   },
 
-  onBeginUpdateBatch: function () {},
-  onEndUpdateBatch: function () {},
+  onBeginUpdateBatch: function () {
+    ++this._batchDepth;
+  },
+  onEndUpdateBatch: function () {
+    if (--this._batchDepth === 0 && this._batchSawScoreIncrement) {
+      this.score += SCORE_INCREMENT_XLARGE;
+    }
+  },
   onItemVisited: function () {}
 };
--- a/services/sync/tests/unit/test_bookmark_tracker.js
+++ b/services/sync/tests/unit/test_bookmark_tracker.js
@@ -1,12 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://gre/modules/PlacesUtils.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://services-sync/bookmark_utils.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines/bookmarks.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 
 Service.engineManager.register(BookmarksEngine);
@@ -106,16 +107,72 @@ add_task(function* test_tracking() {
     do_check_eq(tracker.score, 0);
 
   } finally {
     _("Clean up.");
     yield cleanup();
   }
 });
 
+add_task(function* test_batch_tracking() {
+  _("Test tracker does the correct thing during and after a places 'batch'");
+
+  yield startTracking();
+
+  PlacesUtils.bookmarks.runInBatchMode({
+    runBatched: function() {
+      let folder = PlacesUtils.bookmarks.createFolder(
+        PlacesUtils.bookmarks.bookmarksMenuFolder,
+        "Test Folder", PlacesUtils.bookmarks.DEFAULT_INDEX);
+      // We should be tracking the new folder and its parent (and need to jump
+      // through blocking hoops...)
+      Async.promiseSpinningly(Task.spawn(verifyTrackedCount(2)));
+      // But not have bumped the score.
+      do_check_eq(tracker.score, 0);
+    }
+  }, null);
+
+  // Out of batch mode - tracker should be the same, but score should be up.
+  yield verifyTrackedCount(2);
+  do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+  yield cleanup();
+});
+
+add_task(function* test_nested_batch_tracking() {
+  _("Test tracker does the correct thing if a places 'batch' is nested");
+
+  yield startTracking();
+
+  PlacesUtils.bookmarks.runInBatchMode({
+    runBatched: function() {
+
+      PlacesUtils.bookmarks.runInBatchMode({
+        runBatched: function() {
+          let folder = PlacesUtils.bookmarks.createFolder(
+            PlacesUtils.bookmarks.bookmarksMenuFolder,
+            "Test Folder", PlacesUtils.bookmarks.DEFAULT_INDEX);
+          // We should be tracking the new folder and its parent (and need to jump
+          // through blocking hoops...)
+          Async.promiseSpinningly(Task.spawn(verifyTrackedCount(2)));
+          // But not have bumped the score.
+          do_check_eq(tracker.score, 0);
+        }
+      }, null);
+      _("inner batch complete.");
+      // should still not have a score as the outer batch is pending.
+      do_check_eq(tracker.score, 0);
+    }
+  }, null);
+
+  // Out of both batches - tracker should be the same, but score should be up.
+  yield verifyTrackedCount(2);
+  do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+  yield cleanup();
+});
+
 add_task(function* test_onItemAdded() {
   _("Items inserted via the synchronous bookmarks API should be tracked");
 
   try {
     yield startTracking();
 
     _("Insert a folder using the sync API");
     let syncFolderID = PlacesUtils.bookmarks.createFolder(
@@ -976,23 +1033,23 @@ add_task(function* test_onItemMoved_setI
     // PlacesUtils.bookmarks.setItemIndex.
     let txn = new PlacesSortFolderByNameTransaction(folder_id);
 
     // We're reordering items within the same folder, so only the folder
     // should be tracked.
     _("Execute the sort folder transaction");
     txn.doTransaction();
     yield verifyTrackedItems([folder_guid]);
-    do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+    do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
     yield resetTracker();
 
     _("Undo the sort folder transaction");
     txn.undoTransaction();
     yield verifyTrackedItems([folder_guid]);
-    do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+    do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
   } finally {
     _("Clean up.");
     yield cleanup();
   }
 });
 
 add_task(function* test_onItemDeleted_removeFolderTransaction() {
   _("Folders removed in a transaction should be tracked");
--- a/taskcluster/ci/legacy/tasks/builds/b2g_aries_spark_debug.yml
+++ b/taskcluster/ci/legacy/tasks/builds/b2g_aries_spark_debug.yml
@@ -17,21 +17,17 @@ task:
       level-{{level}}-{{project}}-build-aries-debug-objdir-gecko: /home/worker/objdir-gecko
     env:
       TARGET: 'aries'
       DEBUG: 0
       VARIANT: userdebug
       GAIA_OPTIMIZE: '1'
       B2G_SYSTEM_APPS: '1'
       MOZHARNESS_CONFIG: b2g/taskcluster-spark.py
-    command:
-      - >
-        checkout-gecko workspace &&
-        cd ./workspace/gecko/taskcluster/scripts/phone-builder &&
-        buildbot_step 'Build' ./build-phone.sh $HOME/workspace
+    command: ["/bin/bash", "-c", "checkout-gecko workspace && cd ./workspace/gecko/taskcluster/scripts/phone-builder && buildbot_step 'Build' ./build-phone.sh $HOME/workspace"]
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
       groupSymbol: Aries
       groupName: Aries Device Image
--- a/taskcluster/ci/legacy/tasks/builds/b2g_phone_eng_base.yml
+++ b/taskcluster/ci/legacy/tasks/builds/b2g_phone_eng_base.yml
@@ -9,13 +9,9 @@ task:
       VARIANT: eng
       GAIA_OPTIMIZE: '1'
       B2G_SYSTEM_APPS: '1'
       MOZ_TELEMETRY_REPORTING: '1'
       MOZ_CRASHREPORTER_NO_REPORT: '1'
       GAIA_KEYBOARD_LAYOUTS: 'en,pt-BR,es,de,fr,pl,zh-Hans-Pinyin,zh-Hant-Zhuyin,en-Dvorak'
       B2G_UPDATE_CHANNEL: 'default'
       MOZHARNESS_CONFIG: b2g/taskcluster-phone-eng.py
-    command:
-      - >
-        checkout-gecko workspace &&
-        cd ./workspace/gecko/taskcluster/scripts/phone-builder &&
-        buildbot_step 'Build' ./build-phone.sh $HOME/workspace
+    command: ["/bin/bash", "-c", "checkout-gecko workspace && cd ./workspace/gecko/taskcluster/scripts/phone-builder && buildbot_step 'Build' ./build-phone.sh $HOME/workspace"]
--- a/taskcluster/docs/taskgraph.rst
+++ b/taskcluster/docs/taskgraph.rst
@@ -158,18 +158,22 @@ parameter file.  The parameter keys and 
 Finally, the ``mach taskgraph decision`` subcommand performs the entire
 task-graph generation process, then creates the tasks.  This command should
 only be used within a decision task, as it assumes it is running in that
 context.
 
 Taskgraph JSON Format
 ---------------------
 
-Each task in the graph is represented as a JSON object.  The output is suitable
-for processing with the `jq <https://stedolan.github.io/jq/>`_ utility.
+Task graphs -- both the graph artifacts produced by the decision task and those
+output by the ``--json`` option to the ``mach taskgraph`` commands -- are JSON
+objects, keyed by label, or for optimized task graphs, by taskId.  For
+convenience, the decision task also writes out ``label-to-taskid.json``
+containing a mapping from label to taskId.  Each task in the graph is
+represented as a JSON object.
 
 Each task has the following properties:
 
 ``task_id``
    The task's taskId (only for optimized task graphs)
 
 ``label``
    The task's label
@@ -197,12 +201,16 @@ in the content:
   That is, just collections of tasks without any dependencies indicated.
 
 * The ``optimized`` subcommand returns tasks that have been assigned taskIds.
   The dependencies array, too, contains taskIds instead of labels, with
   dependencies on optimized tasks omitted.  However, the ``task.dependencies``
   array is populated with the full list of dependency taskIds.  All task
   references are resolved in the optimized graph.
 
-The graph artifacts produced by the decision task are JSON objects, keyed by
-label (``full-task-graph.json`` and ``target-tasks``) or by taskId
-(``task-graph.json``).  For convenience, the decision task also writes out
-``label-to-taskid.json`` containing a mapping from label to taskId.
+The output of the ``mach taskgraph`` commands are suitable for processing with
+the `jq <https://stedolan.github.io/jq/>`_ utility.  For example, to extract all
+tasks' labels and their dependencies:
+
+.. code-block:: shell
+
+    jq 'to_entries | map({label: .value.label, dependencies: .value.dependencies})'
+
--- a/taskcluster/mach_commands.py
+++ b/taskcluster/mach_commands.py
@@ -32,17 +32,17 @@ class ShowTaskGraphSubCommand(SubCommand
             CommandArgument('--root', '-r', default='taskcluster/ci',
                             help="root of the taskgraph definition relative to topsrcdir"),
             CommandArgument('--quiet', '-q', action="store_true",
                             help="suppress all logging output"),
             CommandArgument('--verbose', '-v', action="store_true",
                             help="include debug-level logging output"),
             CommandArgument('--json', '-J', action="store_const",
                             dest="format", const="json",
-                            help="Output each task in the task graph as a JSON object"),
+                            help="Output task graph as a JSON object"),
             CommandArgument('--labels', '-L', action="store_const",
                             dest="format", const="labels",
                             help="Output the label for each task in the task graph (default)"),
             CommandArgument('--parameters', '-p', required=True,
                             help="parameters file (.yml or .json; see "
                                  "`taskcluster/docs/parameters.rst`)`"),
             CommandArgument('--no-optimize', dest="optimize", action="store_false",
                             default="true",
@@ -194,20 +194,18 @@ class MachCommands(MachCommandBase):
             traceback.print_exc()
             sys.exit(1)
 
     def show_taskgraph_labels(self, taskgraph):
         for label in taskgraph.graph.visit_postorder():
             print(label)
 
     def show_taskgraph_json(self, taskgraph):
-        # JSON output is a sequence of JSON objects, rather than a single object, so
-        # disassemble the dictionary
-        for task in taskgraph.to_json().itervalues():
-            print(json.dumps(task))
+        print(json.dumps(taskgraph.to_json(),
+              sort_keys=True, indent=2, separators=(',', ': ')))
 
 
 @CommandProvider
 class LoadImage(object):
     @Command('taskcluster-load-image', category="ci",
              description="Load a pre-built Docker image")
     @CommandArgument('--task-id',
                      help="Load the image at public/image.tar in this task,"
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -653,17 +653,17 @@ GeckoDriver.prototype.setUpProxy = funct
           if (proxy.socksVersion) {
             Preferences.set("network.proxy.socks_version", proxy.socksVersion);
           }
         }
         break;
 
       case "PAC":
         Preferences.set("network.proxy.type", 2);
-        Preferences.set("network.proxy.autoconfig_url", proxy.pacUrl);
+        Preferences.set("network.proxy.autoconfig_url", proxy.proxyAutoconfigUrl);
         break;
 
       case "AUTODETECT":
         Preferences.set("network.proxy.type", 4);
         break;
 
       case "SYSTEM":
         Preferences.set("network.proxy.type", 5);
--- a/testing/marionette/harness/marionette/tests/unit/test_proxy.py
+++ b/testing/marionette/harness/marionette/tests/unit/test_proxy.py
@@ -61,31 +61,31 @@ class TestProxy(MarionetteTestCase):
         self.assertEqual(result["proxyType"], 5)
 
     def test_we_can_set_a_pac_proxy(self):
         url = "http://marionette.test"
         capabilities = {"requiredCapabilities":
                             {
                                 "proxy":{
                                     "proxyType": "pac",
-                                    "pacUrl": url,
+                                    "proxyAutoconfigUrl": url,
                                 }
                             }
                         }
         self.marionette.start_session(capabilities)
         result = None
         with self.marionette.using_context('chrome'):
             result = self.marionette.execute_script("""return {
                 "proxyType" : Services.prefs.getIntPref('network.proxy.type'),
-                "pacUrl" : Services.prefs.getCharPref('network.proxy.autoconfig_url'),
+                "proxyAutoconfigUrl" : Services.prefs.getCharPref('network.proxy.autoconfig_url'),
                 }
             """)
 
         self.assertEqual(result["proxyType"], 2)
-        self.assertEqual(result["pacUrl"], url, 'pacUrl was not set')
+        self.assertEqual(result["proxyAutoconfigUrl"], url, 'proxyAutoconfigUrl was not set')
 
     def test_that_we_can_set_a_manual_proxy(self):
         port = 4444
         url = "http://marionette.test"
         capabilities = {"requiredCapabilities":
                             {
                                 "proxy":{
                                     "proxyType": "manual",
--- a/testing/mozharness/configs/firefox_ui_tests/qa_jenkins.py
+++ b/testing/mozharness/configs/firefox_ui_tests/qa_jenkins.py
@@ -1,43 +1,19 @@
 # Default configuration as used by Mozmill CI (Jenkins)
 
-import os
-import sys
-
-import mozharness
-
-
-external_tools_path = os.path.join(
-    os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))),
-    'external_tools',
-)
 
 config = {
     # Tests run in mozmill-ci do not use RelEng infra
     'developer_mode': True,
 
     'env': {
         'PIP_TRUSTED_HOST': 'pypi.pub.build.mozilla.org',
     },
 
-    # General local variable overwrite
-    'exes': {
-        'gittool.py': [
-            # Bug 1227079 - Python executable eeded to get it executed on Windows
-            sys.executable,
-            os.path.join(external_tools_path, 'gittool.py')
-        ],
-        'hgtool.py': [
-            # Bug 1227079 - Python executable eeded to get it executed on Windows
-            sys.executable,
-            os.path.join(external_tools_path, 'hgtool.py')
-        ],
-    },
-
     # PIP
     'find_links': ['http://pypi.pub.build.mozilla.org/pub'],
     'pip_index': False,
 
     # mozcrash support
     'download_minidump_stackwalk': True,
     'download_symbols': 'ondemand',
     'download_tooltool': True,
--- a/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py
+++ b/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py
@@ -1,66 +1,58 @@
 #!/usr/bin/env python
 # ***** BEGIN LICENSE BLOCK *****
 # 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/.
 # ***** END LICENSE BLOCK *****
-"""firefox_ui_updates.py
 
-Author: Armen Zambrano G.
-        Henrik Skupin
-"""
+
 import copy
 import os
 import sys
-import urlparse
 
 from mozharness.base.log import FATAL, WARNING
 from mozharness.base.python import PostScriptRun, PreScriptAction
 from mozharness.mozilla.structuredlog import StructuredOutputParser
 from mozharness.mozilla.testing.testbase import (
     TestingMixin,
     testing_config_options,
 )
 from mozharness.mozilla.vcstools import VCSToolsScript
 
-deprecated_options = [
-    # TODO update mozmill-ci jobs to use --disable-e10s instead?
-    [["--e10s"], {
-        'dest': 'e10s',
-        'action': 'store_true',
-        'default': False,
-        'help': 'Enable multi-process (e10s) mode when running tests.',
-    }],
-]
 
 # General command line arguments for Firefox ui tests
 firefox_ui_tests_config_options = [
     [['--dry-run'], {
         'dest': 'dry_run',
         'default': False,
         'help': 'Only show what was going to be tested.',
     }],
+    [["--e10s"], {
+        'dest': 'e10s',
+        'action': 'store_true',
+        'default': False,
+        'help': 'Enable multi-process (e10s) mode when running tests.',
+    }],
     [['--firefox-ui-branch'], {
         'dest': 'firefox_ui_branch',
         'help': 'which branch to use for firefox_ui_tests',
     }],
     [['--firefox-ui-repo'], {
         'dest': 'firefox_ui_repo',
         'default': 'https://github.com/mozilla/firefox-ui-tests.git',
         'help': 'which firefox_ui_tests repo to use',
     }],
     [['--symbols-path=SYMBOLS_PATH'], {
         'dest': 'symbols_path',
         'help': 'absolute path to directory containing breakpad '
                 'symbols, or the url of a zip file containing symbols.',
     }],
-] + deprecated_options \
-    + copy.deepcopy(testing_config_options)
+] + copy.deepcopy(testing_config_options)
 
 # Command line arguments for update tests
 firefox_ui_update_harness_config_options = [
     [['--update-allow-mar-channel'], {
         'dest': 'update_allow_mar_channel',
         'help': 'Additional MAR channel to be allowed for updates, e.g. '
                 '"firefox-mozilla-beta" for updating a release build to '
                 'the latest beta build.',
@@ -116,97 +108,60 @@ class FirefoxUITests(TestingMixin, VCSTo
         ]
 
         super(FirefoxUITests, self).__init__(
             config_options=config_options,
             all_actions=all_actions or actions,
             default_actions=default_actions or actions,
             *args, **kwargs)
 
-        # As long as we don't run on buildbot the following properties have be set on our own
+        # Code which doesn't run on buildbot has to include the following properties
         self.binary_path = self.config.get('binary_path')
         self.installer_path = self.config.get('installer_path')
         self.installer_url = self.config.get('installer_url')
         self.test_packages_url = self.config.get('test_packages_url')
         self.test_url = self.config.get('test_url')
 
         self.reports = {'html': 'report.html', 'xunit': 'report.xml'}
 
-        self.firefox_ui_repo = self.config['firefox_ui_repo']
-        self.firefox_ui_branch = self.config.get('firefox_ui_branch')
-
-        if not self.test_url and not self.test_packages_url and not self.firefox_ui_branch:
+        if not self.test_url and not self.test_packages_url:
             self.fatal(
-                'You must use --test-url, --test-packages-url, or --firefox-ui-branch (valid '
-                'values can be found at: https://github.com/mozilla/firefox-ui-tests/branches)')
+                'You must use --test-url, or --test-packages-url')
 
     @PreScriptAction('create-virtualenv')
     def _pre_create_virtualenv(self, action):
         dirs = self.query_abs_dirs()
 
-        # If tests are used from common.tests.zip install every Python package
-        # via the single requirements file
-        if self.test_packages_url or self.test_url:
-            requirements = os.path.join(dirs['abs_test_install_dir'],
-                                        'config', 'firefox_ui_requirements.txt')
-            self.register_virtualenv_module(requirements=[requirements], two_pass=True)
-
-        # We have a non-packaged version of Firefox UI tests. So install requirements
-        # and the firefox-ui-tests package separately
-        # TODO - Can be removed when the github repository is no longer needed
-        else:
-            # Register all modules for firefox-ui-tests including all dependencies
-            # as strict versions to ensure newer releases won't break something
-            requirements = os.path.join(dirs['abs_test_install_dir'],
-                                        'requirements.txt')
-            self.register_virtualenv_module(requirements=[requirements])
-
-    def checkout(self):
-        """Clone the firefox-ui-tests repository."""
-        dirs = self.query_abs_dirs()
-
-        self.vcs_checkout(
-            repo=self.firefox_ui_repo,
-            dest=dirs['abs_test_install_dir'],
-            branch=self.firefox_ui_branch,
-            vcs='gittool',
-            env=self.query_env(),
-        )
+        requirements = os.path.join(dirs['abs_test_install_dir'],
+                                    'config', 'firefox_ui_requirements.txt')
+        self.register_virtualenv_module(requirements=[requirements], two_pass=True)
 
     def clobber(self):
         """Delete the working directory"""
         super(FirefoxUITests, self).clobber()
 
         # Also ensure to delete the reports directory to get rid of old files
         dirs = self.query_abs_dirs()
         self.rmtree(dirs['abs_reports_dir'], error_level=FATAL)
 
     def download_and_extract(self):
         """Overriding method from TestingMixin for more specific behavior.
 
         We use the test_packages_url command line argument to check where to get the
         harness, puppeteer, and tests from and how to set them up.
 
         """
-        if self.test_packages_url or self.test_url:
-            target_unzip_dirs = ['config/*',
-                                 'firefox-ui/*',
-                                 'marionette/*',
-                                 'mozbase/*',
-                                 'puppeteer/*',
-                                 'tools/wptserve/*',
-                                 ]
-            super(FirefoxUITests, self).download_and_extract(target_unzip_dirs=target_unzip_dirs)
-
-        else:
-            self.checkout()
-            self._download_installer()
-
-            if self.config.get('download_symbols'):
-                self._download_and_extract_symbols()
+        target_unzip_dirs = ['config/*',
+                             'firefox-ui/*',
+                             'marionette/*',
+                             'mozbase/*',
+                             'puppeteer/*',
+                             'tools/wptserve/*',
+                             ]
+        super(FirefoxUITests, self).download_and_extract(target_unzip_dirs=target_unzip_dirs)
 
     def query_abs_dirs(self):
         if self.abs_dirs:
             return self.abs_dirs
 
         abs_dirs = super(FirefoxUITests, self).query_abs_dirs()
         abs_tests_install_dir = os.path.join(abs_dirs['abs_work_dir'], 'tests')
 
@@ -238,43 +193,16 @@ class FirefoxUITests(TestingMixin, VCSTo
             if name:
                 if type(name) is bool:
                     args.append(option[0][0])
                 else:
                     args.extend([option[0][0], self.config[dest]])
 
         return args
 
-    def query_minidump_stackwalk(self):
-        """Download the minidump stackwalk binary.
-
-        We can remove this whole method once we no longer need the github repository.
-
-        """
-        # If the test package is available use it
-        if self.test_packages_url or self.test_url:
-            return super(FirefoxUITests, self).query_minidump_stackwalk()
-
-        # Otherwise grab the manifest file from hg.mozilla.org
-        manifest_path = None
-
-        if self.config.get('download_minidump_stackwalk'):
-            tooltool_manifest = self.query_minidump_tooltool_manifest()
-            url_base = 'https://hg.mozilla.org/mozilla-central/raw-file/default/testing/'
-
-            dirs = self.query_abs_dirs()
-            manifest_path = os.path.join(dirs['abs_work_dir'], 'releng.manifest')
-            try:
-                self.download_file(urlparse.urljoin(url_base, tooltool_manifest),
-                                   manifest_path)
-            except Exception as e:
-                self.fatal('Download of tooltool manifest file failed: %s' % e.message)
-
-        return super(FirefoxUITests, self).query_minidump_stackwalk(manifest=manifest_path)
-
     @PostScriptRun
     def copy_logs_to_upload_dir(self):
         """Overwrite this method so we also upload the other (e.g. report) files"""
         # Copy logs and report files to the upload folder
         super(FirefoxUITests, self).copy_logs_to_upload_dir()
 
         dirs = self.query_abs_dirs()
         self.info("Copying reports to upload dir...")
@@ -359,63 +287,16 @@ class FirefoxUITests(TestingMixin, VCSTo
 
     def run_tests(self):
         """Run all the tests"""
         return self.run_test(
             binary_path=self.binary_path,
             env=self.query_env(),
         )
 
-    def download_unzip(self, url, parent_dir, target_unzip_dirs=None, halt_on_failure=True):
-        """Overwritten method from BaseScript until bug 1237706 is fixed.
-
-        The downloaded file will always be saved to the working directory and is not getting
-        deleted after extracting.
-
-        Args:
-            url (str): URL where the file to be downloaded is located.
-            parent_dir (str): directory where the downloaded file will
-                              be extracted to.
-            target_unzip_dirs (list, optional): directories inside the zip file to extract.
-                                                Defaults to `None`.
-            halt_on_failure (bool, optional): whether or not to redefine the
-                                              log level as `FATAL` on errors. Defaults to True.
-
-        """
-        import fnmatch
-        import itertools
-        import functools
-        import zipfile
-
-        def _filter_entries(namelist):
-            """Filter entries of the archive based on the specified list of extract_dirs."""
-            filter_partial = functools.partial(fnmatch.filter, namelist)
-            for entry in itertools.chain(*map(filter_partial, target_unzip_dirs or ['*'])):
-                yield entry
-
-        dirs = self.query_abs_dirs()
-        zip = self.download_file(url, parent_dir=dirs['abs_work_dir'],
-                                 error_level=FATAL)
-
-        try:
-            self.info('Using ZipFile to extract {} to {}'.format(zip, parent_dir))
-            with zipfile.ZipFile(zip) as bundle:
-                for entry in _filter_entries(bundle.namelist()):
-                    bundle.extract(entry, path=parent_dir)
-
-                    # ZipFile doesn't preserve permissions: http://bugs.python.org/issue15795
-                    fname = os.path.realpath(os.path.join(parent_dir, entry))
-                    mode = bundle.getinfo(entry).external_attr >> 16 & 0x1FF
-                    # Only set permissions if attributes are available.
-                    if mode:
-                        os.chmod(fname, mode)
-        except zipfile.BadZipfile as e:
-            self.log('%s (%s)' % (e.message, zip),
-                     level=FATAL, exit_code=2)
-
 
 class FirefoxUIFunctionalTests(FirefoxUITests):
 
     cli_script = 'cli_functional.py'
     default_tests = [
         os.path.join('puppeteer', 'manifest.ini'),
         os.path.join('functional', 'manifest.ini'),
     ]
--- a/testing/web-platform/tests/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html
+++ b/testing/web-platform/tests/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html
@@ -99,25 +99,25 @@ test(function(t) {
                            endDelay: -5000,
                            fill: 'forwards' });
 
   anim.currentTime = 1000;
   assert_equals(getComputedStyle(div).opacity, '0.9',
                 'set currentTime before endTime');
 
   anim.currentTime = 5000;
-  assert_equals(getComputedStyle(div).opacity, '0',
+  assert_equals(getComputedStyle(div).opacity, '0.5',
                 'set currentTime same as endTime');
 
   anim.currentTime = 9999;
-  assert_equals(getComputedStyle(div).opacity, '0',
+  assert_equals(getComputedStyle(div).opacity, '0.5',
                 'set currentTime during duration');
 
   anim.currentTime = 10000;
-  assert_equals(getComputedStyle(div).opacity, '0',
+  assert_equals(getComputedStyle(div).opacity, '0.5',
                 'set currentTime after endTime');
 }, 'change currentTime when fill forwards and endDelay is negative');
 
 test(function(t) {
   var div = createDiv(t);
   var anim = div.animate({ opacity: [ 0, 1 ] },
                          { duration: 10000,
                            direction: 'normal' });
--- a/testing/web-platform/tests/web-animations/timing-model/animation-effects/active-time.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animation-effects/active-time.html
@@ -1,24 +1,142 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
 <title>Active time tests</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#active-time">
+<link rel="help" href="https://w3c.github.io/web-animations/#calculating-the-active-time">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
-async_test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, { delay: 1 });
+test(function(t) {
+  var tests = [ { fill: 'none', progress: null },
+                { fill: 'backwards', progress: 0 },
+                { fill: 'forwards', progress: null },
+                { fill: 'both', progress: 0 } ];
+  tests.forEach(function(test) {
+    var anim = createDiv(t).animate(null, { delay: 1, fill: test.fill });
+    assert_equals(anim.effect.getComputedTiming().progress, test.progress,
+                  'Progress in before phase when using \'' + test.fill
+                  + '\' fill');
+  });
+}, 'Active time in before phase');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, 1000);
+  anim.currentTime = 500;
+  assert_times_equal(anim.effect.getComputedTiming().progress, 0.5);
+}, 'Active time in active phase and no start delay is the local time');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { duration: 1000, delay: 500 });
+  anim.currentTime = 1000;
+  assert_times_equal(anim.effect.getComputedTiming().progress, 0.5);
+}, 'Active time in active phase and positive start delay is the local time'
+   + ' minus the start delay');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { duration: 1000, delay: -500 });
+  assert_times_equal(anim.effect.getComputedTiming().progress, 0.5);
+}, 'Active time in active phase and negative start delay is the local time'
+   + ' minus the start delay');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null);
+  assert_equals(anim.effect.getComputedTiming().progress, null);
+}, 'Active time in after phase with no fill is unresolved');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { fill: 'backwards' });
   assert_equals(anim.effect.getComputedTiming().progress, null);
-  anim.finished.then(t.step_func(function() {
-    assert_equals(anim.effect.getComputedTiming().progress, null);
-    t.done();
-  }));
-}, 'Test progress during before and after phase when fill is none');
+}, 'Active time in after phase with backwards-only fill is unresolved');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { duration: 1000,
+                                          iterations: 2.3,
+                                          delay: 500, // Should have no effect
+                                          fill: 'forwards' });
+  anim.finish();
+  assert_equals(anim.effect.getComputedTiming().currentIteration, 2);
+  assert_times_equal(anim.effect.getComputedTiming().progress, 0.3);
+}, 'Active time in after phase with forwards fill is the active duration');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { duration: 0,
+                                          iterations: Infinity,
+                                          fill: 'forwards' });
+  anim.finish();
+  assert_equals(anim.effect.getComputedTiming().currentIteration, Infinity);
+  assert_equals(anim.effect.getComputedTiming().progress, 1);
+}, 'Active time in after phase with forwards fill, zero-duration, and '
+   + ' infinite iteration count is the active duration');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { duration: 1000,
+                                          iterations: 2.3,
+                                          delay: 500,
+                                          endDelay: 4000,
+                                          fill: 'forwards' });
+  anim.finish();
+  assert_equals(anim.effect.getComputedTiming().currentIteration, 2);
+  assert_times_equal(anim.effect.getComputedTiming().progress, 0.3);
+}, 'Active time in after phase with forwards fill and positive end delay'
+   + ' is the active duration');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { duration: 1000,
+                                          iterations: 2.3,
+                                          delay: 500,
+                                          endDelay: -800,
+                                          fill: 'forwards' });
+  anim.finish();
+  assert_equals(anim.effect.getComputedTiming().currentIteration, 1);
+  assert_times_equal(anim.effect.getComputedTiming().progress, 0.5);
+}, 'Active time in after phase with forwards fill and negative end delay'
+   + ' is the active duration + end delay');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { duration: 1000,
+                                          iterations: 2.3,
+                                          delay: 500,
+                                          endDelay: -3000,
+                                          fill: 'forwards' });
+  anim.finish();
+  assert_equals(anim.effect.getComputedTiming().currentIteration, 0);
+  assert_equals(anim.effect.getComputedTiming().progress, 0);
+}, 'Active time in after phase with forwards fill and negative end delay'
+   + ' greater in magnitude than the active duration is zero');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { duration: 1000,
+                                          iterations: 2.3,
+                                          delay: 500,
+                                          endDelay: -4000,
+                                          fill: 'forwards' });
+  anim.finish();
+  assert_equals(anim.effect.getComputedTiming().currentIteration, 0);
+  assert_equals(anim.effect.getComputedTiming().progress, 0);
+}, 'Active time in after phase with forwards fill and negative end delay'
+   + ' greater in magnitude than the sum of the active duration and start delay'
+   + ' is zero');
+
+test(function(t) {
+  var anim = createDiv(t).animate(null, { duration: 1000,
+                                          iterations: 2.3,
+                                          delay: 500,
+                                          fill: 'both' });
+  anim.finish();
+  assert_equals(anim.effect.getComputedTiming().currentIteration, 2);
+  assert_times_equal(anim.effect.getComputedTiming().progress, 0.3);
+}, 'Active time in after phase with \'both\' fill is the active duration');
+
+test(function(t) {
+  // Create an effect with a non-zero duration so we ensure we're not just
+  // testing the after-phase behavior.
+  var effect = new KeyframeEffect(null, null, 1);
+  assert_equals(effect.getComputedTiming().progress, null);
+}, 'Active time when the local time is unresolved, is unresolved');
 
 </script>
 </body>
--- a/testing/web-platform/tests/web-animations/timing-model/animation-effects/current-iteration.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animation-effects/current-iteration.html
@@ -5,17 +5,17 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
-function executeTests(tests, description) {
+function runTests(tests, description) {
   tests.forEach(function(currentTest) {
     var testParams = '';
     for (var attr in currentTest.input) {
       testParams += ' ' + attr + ':' + currentTest.input[attr];
     }
     test(function(t) {
       var div = createDiv(t);
       var anim = div.animate({ opacity: [ 0, 1 ] }, currentTest.input);
@@ -24,31 +24,38 @@ function executeTests(tests, description
       anim.currentTime = currentTest.input.delay || 0;
       assert_equals(anim.effect.getComputedTiming().currentIteration,
                     currentTest.active);
       if (typeof currentTest.after !== 'undefined') {
         anim.finish();
         assert_equals(anim.effect.getComputedTiming().currentIteration,
                       currentTest.after);
       }
-    }, description + testParams);
+    }, description + ':' + testParams);
   });
 }
 
 async_test(function(t) {
   var div = createDiv(t);
   var anim = div.animate({ opacity: [ 0, 1 ] }, { delay: 1 });
   assert_equals(anim.effect.getComputedTiming().currentIteration, null);
   anim.finished.then(t.step_func(function() {
     assert_equals(anim.effect.getComputedTiming().currentIteration, null);
     t.done();
   }));
 }, 'Test currentIteration during before and after phase when fill is none');
 
-var gTests_zero_iterations = [
+
+// --------------------------------------------------------------------
+//
+// Zero iteration duration tests
+//
+// --------------------------------------------------------------------
+
+runTests([
   {
     input:    { iterations: 0,
                 iterationStart: 0,
                 duration: 0,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 0,
@@ -137,19 +144,26 @@ var gTests_zero_iterations = [
                 iterationStart: 3,
                 duration: Infinity,
                 delay: 1,
                 fill: 'both' },
     before: 3,
     active: 3,
     after: 3
   }
-];
+], 'Test zero iterations');
+
 
-var gTests_integer_iterations = [
+// --------------------------------------------------------------------
+//
+// Tests where the iteration count is an integer
+//
+// --------------------------------------------------------------------
+
+runTests([
   {
     input:    { iterations: 3,
                 iterationStart: 0,
                 duration: 0,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 2,
@@ -235,19 +249,26 @@ var gTests_integer_iterations = [
     input:    { iterations: 3,
                 iterationStart: 3,
                 duration: Infinity,
                 delay: 1,
                 fill: 'both' },
     before: 3,
     active: 3
   }
-];
+], 'Test integer iterations');
+
 
-var gTests_fractional_iterations = [
+// --------------------------------------------------------------------
+//
+// Tests where the iteration count is a fraction
+//
+// --------------------------------------------------------------------
+
+runTests([
   {
     input:    { iterations: 3.5,
                 iterationStart: 0,
                 duration: 0,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 3,
@@ -333,19 +354,26 @@ var gTests_fractional_iterations = [
     input:    { iterations: 3.5,
                 iterationStart: 3,
                 duration: Infinity,
                 delay: 1,
                 fill: 'both' },
     before: 3,
     active: 3
   }
-];
+], 'Test fractional iterations');
+
 
-var gTests_infinity_iterations = [
+// --------------------------------------------------------------------
+//
+// Tests where the iteration count is Infinity
+//
+// --------------------------------------------------------------------
+
+runTests([
   {
     input:    { iterations: Infinity,
                 iterationStart: 0,
                 duration: 0,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: Infinity,
@@ -428,17 +456,129 @@ var gTests_infinity_iterations = [
     input:    { iterations: Infinity,
                 iterationStart: 3,
                 duration: Infinity,
                 delay: 1,
                 fill: 'both' },
     before: 3,
     active: 3
   }
-];
+], 'Test infinity iterations');
+
+
+// --------------------------------------------------------------------
+//
+// End delay tests
+//
+// --------------------------------------------------------------------
+
+runTests([
+  {
+    input:    { duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: 50 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
+
+  {
+    input:    { duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -50 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
+
+  {
+    input:    { duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -100 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
+
+  {
+    input:    { duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -200 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
 
-executeTests(gTests_zero_iterations, "Test zero iterations:");
-executeTests(gTests_integer_iterations, "Test integer iterations:");
-executeTests(gTests_fractional_iterations, "Test fractional iterations:");
-executeTests(gTests_infinity_iterations, "Test infinity iterations:");
+  {
+    input:    { iterationStart: 0.5,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: 50 },
+    before: 0,
+    active: 0,
+    after: 1
+  },
+
+  {
+    input:    { iterationStart: 0.5,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -50 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
+
+  {
+    input:    { iterationStart: 0.5,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -100 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
+
+  {
+    input:    { iterations: 2,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -100 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
+
+  {
+    input:    { iterations: 1,
+                iterationStart: 2,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -50 },
+    before: 2,
+    active: 2,
+    after: 2
+  },
+
+  {
+    input:    { iterations: 1,
+                iterationStart: 2,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -100 },
+    before: 2,
+    active: 2,
+    after: 2
+  },
+], 'Test end delay');
 
 </script>
 </body>
--- a/testing/web-platform/tests/web-animations/timing-model/animation-effects/simple-iteration-progress.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animation-effects/simple-iteration-progress.html
@@ -6,17 +6,17 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
-function executeTests(tests, description) {
+function runTests(tests, description) {
   tests.forEach(function(currentTest) {
     var testParams = '';
     for (var attr in currentTest.input) {
       testParams += ' ' + attr + ':' + currentTest.input[attr];
     }
     test(function(t) {
       var div = createDiv(t);
       var anim = div.animate({ opacity: [ 0, 1 ] }, currentTest.input);
@@ -25,21 +25,28 @@ function executeTests(tests, description
       anim.currentTime = currentTest.input.delay || 0;
       assert_equals(anim.effect.getComputedTiming().progress,
                     currentTest.active);
       if (typeof currentTest.after !== 'undefined') {
         anim.finish();
         assert_equals(anim.effect.getComputedTiming().progress,
                       currentTest.after);
       }
-    }, description + testParams);
+    }, description + ':' + testParams);
   });
 }
 
-var gTests_zero_iterations = [
+
+// --------------------------------------------------------------------
+//
+// Zero iteration duration tests
+//
+// --------------------------------------------------------------------
+
+runTests([
   {
     input:    { iterations: 0,
                 iterationStart: 0,
                 duration: 0,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 0,
@@ -128,19 +135,26 @@ var gTests_zero_iterations = [
                 iterationStart: 3,
                 duration: Infinity,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 0,
     after: 0
   }
-];
+], 'Test zero iterations');
+
 
-var gTests_integer_iterations = [
+// --------------------------------------------------------------------
+//
+// Tests where the iteration count is an integer
+//
+// --------------------------------------------------------------------
+
+runTests([
   {
     input:    { iterations: 3,
                 iterationStart: 0,
                 duration: 0,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 1,
@@ -226,19 +240,26 @@ var gTests_integer_iterations = [
     input:    { iterations: 3,
                 iterationStart: 3,
                 duration: Infinity,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 0
   }
-];
+], 'Test integer iterations');
+
 
-var gTests_fractional_iterations = [
+// --------------------------------------------------------------------
+//
+// Tests where the iteration count is a fraction
+//
+// --------------------------------------------------------------------
+
+runTests([
   {
     input:    { iterations: 3.5,
                 iterationStart: 0,
                 duration: 0,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 0.5,
@@ -324,19 +345,26 @@ var gTests_fractional_iterations = [
     input:    { iterations: 3.5,
                 iterationStart: 3,
                 duration: Infinity,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 0
   }
-];
+], 'Test fractional iterations');
+
 
-var gTests_infinity_iterations = [
+// --------------------------------------------------------------------
+//
+// Tests where the iteration count is Infinity
+//
+// --------------------------------------------------------------------
+
+runTests([
   {
     input:    { iterations: Infinity,
                 iterationStart: 0,
                 duration: 0,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 1,
@@ -419,17 +447,129 @@ var gTests_infinity_iterations = [
     input:    { iterations: Infinity,
                 iterationStart: 3,
                 duration: Infinity,
                 delay: 1,
                 fill: 'both' },
     before: 0,
     active: 0
   }
-];
+], 'Test infinity iterations');
+
+
+// --------------------------------------------------------------------
+//
+// End delay tests
+//
+// --------------------------------------------------------------------
+
+runTests([
+  {
+    input:    { duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: 50 },
+    before: 0,
+    active: 0,
+    after: 1
+  },
+
+  {
+    input:    { duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -50 },
+    before: 0,
+    active: 0,
+    after: 0.5
+  },
+
+  {
+    input:    { duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -100 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
+
+  {
+    input:    { duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -200 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
 
-executeTests(gTests_zero_iterations, "Test zero iterations:");
-executeTests(gTests_integer_iterations, "Test integer iterations:");
-executeTests(gTests_fractional_iterations, "Test fractional iterations:");
-executeTests(gTests_infinity_iterations, "Test infinity iterations:");
+  {
+    input:    { iterationStart: 0.5,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: 50 },
+    before: 0.5,
+    active: 0.5,
+    after: 0.5
+  },
+
+  {
+    input:    { iterationStart: 0.5,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -50 },
+    before: 0.5,
+    active: 0.5,
+    after: 1
+  },
+
+  {
+    input:    { iterationStart: 0.5,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -100 },
+    before: 0.5,
+    active: 0.5,
+    after: 0.5
+  },
+
+  {
+    input:    { iterations: 2,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -100 },
+    before: 0,
+    active: 0,
+    after: 1
+  },
+
+  {
+    input:    { iterations: 1,
+                iterationStart: 2,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -50 },
+    before: 0,
+    active: 0,
+    after: 0.5
+  },
+
+  {
+    input:    { iterations: 1,
+                iterationStart: 2,
+                duration: 100,
+                delay: 1,
+                fill: 'both',
+                endDelay: -100 },
+    before: 0,
+    active: 0,
+    after: 0
+  },
+], 'Test end delay');
 
 </script>
 </body>
--- a/toolkit/components/prompts/content/commonDialog.css
+++ b/toolkit/components/prompts/content/commonDialog.css
@@ -8,15 +8,15 @@
   max-width: 45em;
 }
 
 #info\.body {
   -moz-user-focus: normal;
   -moz-user-select: text;
   cursor: text !important;
   white-space: pre-wrap;
-  unicode-bidi: -moz-plaintext;
+  unicode-bidi: plaintext;
 }
 
 #loginLabel, #password1Label {
   text-align: right;
 }
 
--- a/toolkit/components/prompts/content/tabprompts.css
+++ b/toolkit/components/prompts/content/tabprompts.css
@@ -21,14 +21,14 @@ tabmodalprompt {
 }
 
 .info\.body {
   margin: 0 !important;
   -moz-user-focus: normal;
   -moz-user-select: text;
   cursor: text !important;
   white-space: pre-wrap;
-  unicode-bidi: -moz-plaintext;
+  unicode-bidi: plaintext;
 }
 
 label[value=""] {
   visibility: collapse;
 }
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -7345,16 +7345,21 @@ AddonWrapper.prototype = {
 
     if (addon.inDatabase) {
       if (addon.type == "theme" && val) {
         if (addon.internalName == XPIProvider.defaultSkin)
           throw new Error("Cannot disable the default theme");
         XPIProvider.enableDefaultTheme();
       }
       else {
+        // hidden and system add-ons should not be user disasbled,
+        // as there is no UI to re-enable them.
+        if (this.hidden) {
+          throw new Error(`Cannot disable hidden add-on ${addon.id}`);
+        }
         XPIProvider.updateAddonDisabledState(addon, val);
       }
     }
     else {
       addon.userDisabled = val;
       // When enabling remove the softDisabled flag
       if (!val)
         addon.softDisabled = false;
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_nodisable_hidden.js
@@ -0,0 +1,107 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// This test verifies that hidden add-ons cannot be user disabled.
+
+// for normal add-ons
+const profileDir = FileUtils.getDir("ProfD", ["extensions"]);
+// for system add-ons
+const distroDir = FileUtils.getDir("ProfD", ["sysfeatures"], true);
+registerDirectory("XREAppFeat", distroDir);
+
+const NORMAL_ID = "normal@tests.mozilla.org";
+const SYSTEM_ID = "system@tests.mozilla.org";
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
+
+// normal add-ons can be user disabled.
+add_task(function*() {
+
+  writeInstallRDFToDir({
+    id: NORMAL_ID,
+    version: "1.0",
+    bootstrap: true,
+    targetApplications: [{
+      id: "xpcshell@tests.mozilla.org",
+      minVersion: "1",
+      maxVersion: "1"
+    }],
+    name: "Test disabling hidden add-ons, non-hidden add-on case.",
+  }, profileDir, NORMAL_ID);
+
+  startupManager();
+
+  let addon = yield promiseAddonByID(NORMAL_ID);
+  do_check_neq(addon, null);
+  do_check_eq(addon.version, "1.0");
+  do_check_eq(addon.name, "Test disabling hidden add-ons, non-hidden add-on case.");
+  do_check_true(addon.isCompatible);
+  do_check_false(addon.appDisabled);
+  do_check_false(addon.userDisabled);
+  do_check_true(addon.isActive);
+  do_check_eq(addon.type, "extension");
+
+  // normal add-ons can be disabled by the user.
+  addon.userDisabled = true;
+
+  do_check_neq(addon, null);
+  do_check_eq(addon.version, "1.0");
+  do_check_eq(addon.name, "Test disabling hidden add-ons, non-hidden add-on case.");
+  do_check_true(addon.isCompatible);
+  do_check_false(addon.appDisabled);
+  do_check_true(addon.userDisabled);
+  do_check_false(addon.isActive);
+  do_check_eq(addon.type, "extension");
+
+  addon.uninstall();
+
+  shutdownManager();
+});
+
+// system add-ons can never be user disabled.
+add_task(function*() {
+
+  writeInstallRDFToDir({
+    id: SYSTEM_ID,
+    version: "1.0",
+    bootstrap: true,
+    targetApplications: [{
+      id: "xpcshell@tests.mozilla.org",
+      minVersion: "1",
+      maxVersion: "1"
+    }],
+    name: "Test disabling hidden add-ons, hidden system add-on case.",
+  }, distroDir, SYSTEM_ID);
+
+  startupManager();
+
+  let addon = yield promiseAddonByID(SYSTEM_ID);
+  do_check_neq(addon, null);
+  do_check_eq(addon.version, "1.0");
+  do_check_eq(addon.name, "Test disabling hidden add-ons, hidden system add-on case.");
+  do_check_true(addon.isCompatible);
+  do_check_false(addon.appDisabled);
+  do_check_false(addon.userDisabled);
+  do_check_true(addon.isActive);
+  do_check_eq(addon.type, "extension");
+
+  // system add-ons cannot be disabled by the user.
+  try {
+    addon.userDisabled = true;
+    do_throw("Expected addon.userDisabled on a hidden add-on to throw!");
+  } catch(e) {
+    do_check_eq(e.message, `Cannot disable hidden add-on ${SYSTEM_ID}`);
+  }
+
+  do_check_neq(addon, null);
+  do_check_eq(addon.version, "1.0");
+  do_check_eq(addon.name, "Test disabling hidden add-ons, hidden system add-on case.");
+  do_check_true(addon.isCompatible);
+  do_check_false(addon.appDisabled);
+  do_check_false(addon.userDisabled);
+  do_check_true(addon.isActive);
+  do_check_eq(addon.type, "extension");
+
+  shutdownManager();
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -32,11 +32,12 @@ skip-if = appname != "firefox"
 [test_system_reset.js]
 [test_XPIcancel.js]
 [test_XPIStates.js]
 [test_temporary.js]
 [test_proxies.js]
 [test_proxy.js]
 [test_pass_symbol.js]
 [test_delay_update.js]
+[test_nodisable_hidden.js]
 
 
 [include:xpcshell-shared.ini]
--- a/widget/windows/nsPrintSettingsWin.cpp
+++ b/widget/windows/nsPrintSettingsWin.cpp
@@ -1,15 +1,143 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "nsPrintSettingsWin.h"
+
+#include "mozilla/ArrayUtils.h"
 #include "nsCRT.h"
 
+// Using paper sizes from wingdi.h and the units given there, plus a little
+// extra research for the ones it doesn't give. Looks like the list hasn't
+// changed since Windows 2000, so should be fairly stable now.
+const short kPaperSizeUnits[] = {
+  nsIPrintSettings::kPaperSizeMillimeters, // Not Used default to mm as DEVMODE
+                                           // uses tenths of mm, just in case
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LETTER
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LETTERSMALL
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_TABLOID
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LEDGER
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LEGAL
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_STATEMENT
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_EXECUTIVE
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4SMALL
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B4
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_FOLIO
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_QUARTO
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_10X14
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_11X17
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_NOTE
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_ENV_9
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_ENV_10
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_ENV_11
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_ENV_12
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_ENV_14
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_CSHEET
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_DSHEET
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_ESHEET
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_DL
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C5
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C3
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C4
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C6
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C65
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B4
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B5
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B6
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_ITALY
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_ENV_MONARCH
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_ENV_PERSONAL
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_FANFOLD_US
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_FANFOLD_STD_GERMAN
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_FANFOLD_LGL_GERMAN
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ISO_B4
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JAPANESE_POSTCARD
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_9X11
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_10X11
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_15X11
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_INVITE
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_RESERVED_48
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_RESERVED_49
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LETTER_EXTRA
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LEGAL_EXTRA
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_TABLOID_EXTRA
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_A4_EXTRA
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LETTER_TRANSVERSE
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_TRANSVERSE
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LETTER_EXTRA_TRANSVERSE
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A_PLUS
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B_PLUS
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LETTER_PLUS
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_PLUS
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_TRANSVERSE
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_TRANSVERSE
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_EXTRA
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_EXTRA
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_EXTRA
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A2
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_TRANSVERSE
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_EXTRA_TRANSVERSE
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_DBL_JAPANESE_POSTCARD
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A6
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU2
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU3
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU3
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU4
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_LETTER_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B4_JIS_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_JIS_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JAPANESE_POSTCARD_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A6_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU2_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU3_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU3_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU4_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B6_JIS
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B6_JIS_ROTATED
+  nsIPrintSettings::kPaperSizeInches,      // DMPAPER_12X11
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_YOU4
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_YOU4_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P16K
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32K
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32KBIG
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_1
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_2
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_3
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_4
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_5
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_6
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_7
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_8
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_9
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_10
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P16K_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32K_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32KBIG_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_1_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_2_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_3_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_4_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_5_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_6_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_7_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_8_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_9_ROTATED
+  nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_10_ROTATED
+};
+
 NS_IMPL_ISUPPORTS_INHERITED(nsPrintSettingsWin, 
                             nsPrintSettings, 
                             nsIPrintSettingsWin)
 
 /** ---------------------------------------------------
  *  See documentation in nsPrintSettingsWin.h
  *	@update 
  */
@@ -181,31 +309,36 @@ nsPrintSettingsWin::CopyFromNative(HDC a
     if (mScaling == 1.0 || scale != 1.0) {
       mScaling = scale;
     }
     aDevMode->dmScale = 100;
   }
 
   if (aDevMode->dmFields & DM_PAPERSIZE) {
     mPaperData = aDevMode->dmPaperSize;
+    // If not a paper size we know about, the unit will be the last one saved.
+    if (mPaperData > 0 &&
+        mPaperData < int32_t(mozilla::ArrayLength(kPaperSizeUnits))) {
+      mPaperSizeUnit = kPaperSizeUnits[mPaperData];
+    }
   } else {
     mPaperData = -1;
   }
 
-  // The length and width in DEVMODE are always in tenths of a millimeter, so
-  // storing them in millimeters is easiest.
-  mPaperSizeUnit = kPaperSizeMillimeters;
+  // The length and width in DEVMODE are always in tenths of a millimeter.
+  double sizeUnitToTenthsOfAmm =
+    10L * (mPaperSizeUnit == kPaperSizeInches ? MM_PER_INCH_FLOAT : 1L);
   if (aDevMode->dmFields & DM_PAPERLENGTH) {
-    mPaperHeight = aDevMode->dmPaperLength / 10l;
+    mPaperHeight = aDevMode->dmPaperLength / sizeUnitToTenthsOfAmm;
   } else {
     mPaperHeight = -1l;
   }
 
   if (aDevMode->dmFields & DM_PAPERWIDTH) {
-    mPaperWidth = aDevMode->dmPaperWidth / 10l;
+    mPaperWidth = aDevMode->dmPaperWidth / sizeUnitToTenthsOfAmm;
   } else {
     mPaperWidth = -1l;
   }
 
   // On Windows we currently create a surface using the printable area of the
   // page and don't set the unwriteable [sic] margins. Using the unwriteable
   // margins doesn't appear to work on Windows, but I am not sure if this is a
   // bug elsewhere in our code or a Windows quirk.
@@ -237,39 +370,32 @@ nsPrintSettingsWin::CopyToNative(DEVMODE
   if (mPaperData >= 0) {
     aDevMode->dmPaperSize = mPaperData;
     aDevMode->dmFields |= DM_PAPERSIZE;
   } else {
     aDevMode->dmPaperSize = 0;
     aDevMode->dmFields &= ~DM_PAPERSIZE;
   }
 
-  double paperHeight;
-  double paperWidth;
-  if (mPaperSizeUnit == kPaperSizeMillimeters) {
-    paperHeight = mPaperHeight;
-    paperWidth = mPaperWidth;
-  } else {
-    paperHeight = mPaperHeight * MM_PER_INCH_FLOAT;
-    paperWidth = mPaperWidth * MM_PER_INCH_FLOAT;
-  }
+  // The length and width in DEVMODE are always in tenths of a millimeter.
+  double sizeUnitToTenthsOfAmm =
+    10L * (mPaperSizeUnit == kPaperSizeInches ? MM_PER_INCH_FLOAT : 1L);
 
   // Note: small page sizes can be required here for sticker, label and slide
   // printers etc. see bug 1271900.
-  if (paperHeight > 0) {
-    // In DEVMODEs, physical lengths are stored in tenths of millimeters.
-    aDevMode->dmPaperLength = paperHeight * 10l;
+  if (mPaperHeight > 0) {
+    aDevMode->dmPaperLength = mPaperHeight * sizeUnitToTenthsOfAmm;
     aDevMode->dmFields |= DM_PAPERLENGTH;
   } else {
     aDevMode->dmPaperLength = 0;
     aDevMode->dmFields &= ~DM_PAPERLENGTH;
   }
 
-  if (paperWidth > 0) {
-    aDevMode->dmPaperWidth = paperWidth * 10l;
+  if (mPaperWidth > 0) {
+    aDevMode->dmPaperWidth = mPaperWidth * sizeUnitToTenthsOfAmm;
     aDevMode->dmFields |= DM_PAPERWIDTH;
   } else {
     aDevMode->dmPaperWidth = 0;
     aDevMode->dmFields &= ~DM_PAPERWIDTH;
   }
 
   // Setup Orientation
   aDevMode->dmOrientation = mOrientation == kPortraitOrientation
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -6796,17 +6796,17 @@ nsWindow::HasBogusPopupsDropShadowOnMult
     // Since any change in the preferences requires a restart, this can be
     // done just once.
     // Check for Direct2D first.
     sHasBogusPopupsDropShadowOnMultiMonitor =
       gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend() ? TRI_TRUE : TRI_FALSE;
     if (!sHasBogusPopupsDropShadowOnMultiMonitor) {
       // Otherwise check if Direct3D 9 may be used.
       if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING) &&
-          !gfxPrefs::LayersPreferOpenGL())
+          !gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING))
       {
         nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
         if (gfxInfo) {
           int32_t status;
           nsCString discardFailureId;
           if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
                                                      discardFailureId, &status))) {
             if (status == nsIGfxInfo::FEATURE_STATUS_OK ||