Merge inbound to mozilla-central. a=merge
authorshindli <shindli@mozilla.com>
Tue, 22 May 2018 00:29:52 +0300
changeset 419182 51f2535c797495f1f4e864072c2449b7c28669de
parent 419154 c8b0df341f44e0e7563d544b76d6d21f7cf12d27 (current diff)
parent 419181 da8925b18399d3740ae0207b01c59d9e2ef0ab1e (diff)
child 419183 a23b4e769ce042895cd9d743384b9603041fd612
child 419201 fa332d9d704da9056d4c7493bcc4b718810c4529
child 419257 47e1f92340c68642f336b7285ef0d34f58d0fe2d
push id34029
push usershindli@mozilla.com
push dateMon, 21 May 2018 21:30:22 +0000
treeherdermozilla-central@51f2535c7974 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
51f2535c7974 / 62.0a1 / 20180521220045 / files
nightly linux64
51f2535c7974 / 62.0a1 / 20180521220045 / files
nightly mac
51f2535c7974 / 62.0a1 / 20180521220045 / files
nightly win32
51f2535c7974 / 62.0a1 / 20180521220045 / files
nightly win64
51f2535c7974 / 62.0a1 / 20180521220045 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
devtools/client/inspector/rules/rules.js
toolkit/components/telemetry/Histograms.json
toolkit/components/telemetry/histogram-whitelists.json
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -26,20 +26,20 @@ const {
   VIEW_NODE_SHAPE_SWATCH,
   VIEW_NODE_VARIABLE_TYPE,
   VIEW_NODE_FONT_TYPE,
 } = require("devtools/client/inspector/shared/node-types");
 const TooltipsOverlay = require("devtools/client/inspector/shared/tooltips-overlay");
 const {createChild, promiseWarn} = require("devtools/client/inspector/shared/utils");
 const {debounce} = require("devtools/shared/debounce");
 const EventEmitter = require("devtools/shared/event-emitter");
-const AutocompletePopup = require("devtools/client/shared/autocomplete-popup");
 
 loader.lazyRequireGetter(this, "ClassListPreviewer", "devtools/client/inspector/rules/views/class-list-previewer");
 loader.lazyRequireGetter(this, "StyleInspectorMenu", "devtools/client/inspector/shared/style-inspector-menu");
+loader.lazyRequireGetter(this, "AutocompletePopup", "devtools/client/shared/autocomplete-popup");
 loader.lazyRequireGetter(this, "KeyShortcuts", "devtools/client/shared/key-shortcuts");
 loader.lazyRequireGetter(this, "clipboardHelper", "devtools/shared/platform/clipboard");
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const PREF_UA_STYLES = "devtools.inspector.showUserAgentStyles";
 const PREF_DEFAULT_COLOR_UNIT = "devtools.defaultColorUnit";
 const PREF_FONT_EDITOR = "devtools.inspector.fonteditor.enabled";
 const FILTER_CHANGED_TIMEOUT = 150;
@@ -171,22 +171,16 @@ function CssRuleView(inspector, document
 
   this._prefObserver = new PrefObserver("devtools.");
   this._prefObserver.on(PREF_UA_STYLES, this._handleUAStylePrefChange);
   this._prefObserver.on(PREF_DEFAULT_COLOR_UNIT, this._handleDefaultColorUnitPrefChange);
 
   this.showUserAgentStyles = Services.prefs.getBoolPref(PREF_UA_STYLES);
   this.showFontEditor = Services.prefs.getBoolPref(PREF_FONT_EDITOR);
 
-  // The popup will be attached to the toolbox document.
-  this.popup = new AutocompletePopup(inspector._toolbox.doc, {
-    autoSelect: true,
-    theme: "auto"
-  });
-
   this._showEmpty();
 
   // Add the tooltips and highlighters to the view
   this.tooltips = new TooltipsOverlay(this);
 
   this.highlighters.addToView(this);
 }
 
@@ -196,16 +190,28 @@ CssRuleView.prototype = {
 
   // Used for cancelling timeouts in the style filter.
   _filterChangedTimeout: null,
 
   // Empty, unconnected element of the same type as this node, used
   // to figure out how shorthand properties will be parsed.
   _dummyElement: null,
 
+  get popup() {
+    if (!this._popup) {
+      // The popup will be attached to the toolbox document.
+      this._popup = new AutocompletePopup(this.inspector.toolbox.doc, {
+        autoSelect: true,
+        theme: "auto",
+      });
+    }
+
+    return this._popup;
+  },
+
   get classListPreviewer() {
     if (!this._classListPreviewer) {
       this._classListPreviewer = new ClassListPreviewer(this.inspector, this.classPanel);
     }
 
     return this._classListPreviewer;
   },
 
@@ -779,17 +785,20 @@ CssRuleView.prototype = {
     if (this.element.parentNode) {
       this.element.remove();
     }
 
     if (this._elementStyle) {
       this._elementStyle.destroy();
     }
 
-    this.popup.destroy();
+    if (this._popup) {
+      this._popup.destroy();
+      this._popup = null;
+    }
   },
 
   /**
    * Mark the view as selecting an element, disabling all interaction, and
    * visually clearing the view after a few milliseconds to avoid confusion
    * about which element's styles the rule view shows.
    */
   _startSelectingElement: function() {
--- a/devtools/client/shared/autocomplete-popup.js
+++ b/devtools/client/shared/autocomplete-popup.js
@@ -1,23 +1,24 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const HTML_NS = "http://www.w3.org/1999/xhtml";
 const Services = require("Services");
+const EventEmitter = require("devtools/shared/event-emitter");
 const {HTMLTooltip} = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
-const EventEmitter = require("devtools/shared/event-emitter");
 const {PrefObserver} = require("devtools/client/shared/prefs");
 const {colorUtils} = require("devtools/shared/css/color");
 
+const HTML_NS = "http://www.w3.org/1999/xhtml";
 let itemIdCounter = 0;
+
 /**
  * Autocomplete popup UI implementation.
  *
  * @constructor
  * @param {Document} toolboxDoc
  *        The toolbox document to attach the autocomplete popup panel.
  * @param {Object} options
  *        An object consiting any of the following options:
--- a/dom/base/UseCounter.h
+++ b/dom/base/UseCounter.h
@@ -30,17 +30,11 @@ enum UseCounter : int16_t {
 #define DEPRECATED_OPERATION(op_) \
   eUseCounter_##op_,
 #include "nsDeprecatedOperationList.h"
 #undef DEPRECATED_OPERATION
 
   eUseCounter_Count
 };
 
-enum IncCounter : int16_t {
-  eIncCounter_UNKNOWN = -1,
-  eIncCounter_ScriptTag,
-  eIncCounter_Count
-};
-
 }
 
 #endif
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1487,36 +1487,32 @@ nsIDocument::nsIDocument()
     mStaticCloneCount(0),
     mWindow(nullptr),
     mBFCacheEntry(nullptr),
     mInSyncOperationCount(0),
     mBlockDOMContentLoaded(0),
     mUseCounters(0),
     mChildDocumentUseCounters(0),
     mNotifiedPageForUseCounter(0),
-    mIncCounters(),
     mUserHasInteracted(false),
     mUserHasActivatedInteraction(false),
     mStackRefCnt(0),
     mUpdateNestLevel(0),
     mViewportType(Unknown),
     mSubDocuments(nullptr),
     mHeaderData(nullptr),
     mFlashClassification(FlashClassification::Unclassified),
     mBoxObjectTable(nullptr),
     mCurrentOrientationAngle(0),
     mCurrentOrientationType(OrientationType::Portrait_primary),
     mServoRestyleRootDirtyBits(0),
     mThrowOnDynamicMarkupInsertionCounter(0),
     mIgnoreOpensDuringUnloadCounter(0)
 {
   SetIsInDocument();
-  for (auto& cnt : mIncCounters) {
-    cnt = 0;
-  }
 }
 
 nsDocument::nsDocument(const char* aContentType)
   : nsIDocument()
 {
   SetContentTypeInternal(nsDependentCString(aContentType));
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
@@ -12154,21 +12150,16 @@ nsIDocument::ReportUseCounters(UseCounte
             printf(": %d\n", value);
           }
 
           Telemetry::Accumulate(id, 1);
         }
       }
     }
   }
-
-  if (IsContentDocument() || IsResourceDoc()) {
-    uint16_t num = mIncCounters[eIncCounter_ScriptTag];
-    Telemetry::Accumulate(Telemetry::DOM_SCRIPT_EVAL_PER_DOCUMENT, num);
-  }
 }
 
 void
 nsIDocument::UpdateIntersectionObservations()
 {
   if (mIntersectionObservers.IsEmpty()) {
     return;
   }
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3376,21 +3376,16 @@ public:
   void SetDocumentAndPageUseCounter(mozilla::UseCounter aUseCounter)
   {
     SetDocumentUseCounter(aUseCounter);
     SetPageUseCounter(aUseCounter);
   }
 
   void PropagateUseCounters(nsIDocument* aParentDocument);
 
-  void SetDocumentIncCounter(mozilla::IncCounter aIncCounter, uint32_t inc = 1)
-  {
-    mIncCounters[aIncCounter] += inc;
-  }
-
   void SetUserHasInteracted(bool aUserHasInteracted);
   bool UserHasInteracted()
   {
     return mUserHasInteracted;
   }
 
   // This would be called when document get activated by specific user gestures
   // and propagate the user activation flag to its parent.
@@ -4236,19 +4231,16 @@ protected:
   // Flags for use counters used directly by this document.
   std::bitset<mozilla::eUseCounter_Count> mUseCounters;
   // Flags for use counters used by any child documents of this document.
   std::bitset<mozilla::eUseCounter_Count> mChildDocumentUseCounters;
   // Flags for whether we've notified our top-level "page" of a use counter
   // for this child document.
   std::bitset<mozilla::eUseCounter_Count> mNotifiedPageForUseCounter;
 
-  // Count the number of times something is seen in a document.
-  mozilla::Array<uint16_t, mozilla::eIncCounter_Count> mIncCounters;
-
   // Whether the user has interacted with the document or not:
   bool mUserHasInteracted;
 
   // Whether the user has interacted with the document via some specific user
   // gestures.
   bool mUserHasActivatedInteraction;
 
   mozilla::TimeStamp mPageUnloadingEventTimeStamp;
--- a/dom/indexedDB/test/browser.ini
+++ b/dom/indexedDB/test/browser.ini
@@ -18,10 +18,10 @@ support-files =
 
 [browser_forgetThisSite.js]
 [browser_permissionsPromptAllow.js]
 [browser_permissionsPromptDeny.js]
 [browser_permissionsPromptWorker.js]
 [browser_perwindow_privateBrowsing.js]
 skip-if = os == 'linux' && debug # bug 1394671
 [browser_private_idb.js]
-skip-if = (os == 'osx' && debug) || (os == 'win' && debug) # Bug 1456325
+skip-if = (os == 'mac' && debug) || (os == 'win' && debug) # Bug 1456325
 [browser_bug839193.js]
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -170,8 +170,11 @@ JAR_MANIFESTS += ['jar.mn']
 BROWSER_CHROME_MANIFESTS += ['tests/browser.ini']
 MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
 
 CXXFLAGS += CONFIG['TK_CFLAGS']
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
+
+if CONFIG['NIGHTLY_BUILD']:
+    DEFINES['ASYNC_CONTENTPROC_LAUNCH'] = True
--- a/dom/performance/PerformanceObserver.cpp
+++ b/dom/performance/PerformanceObserver.cpp
@@ -129,21 +129,20 @@ PerformanceObserver::QueueEntry(Performa
   aEntry->GetEntryType(entryType);
   if (!mEntryTypes.Contains<nsString>(entryType)) {
     return;
   }
 
   mQueuedEntries.AppendElement(aEntry);
 }
 
-static const char16_t *const sValidTypeNames[4] = {
+static const char16_t *const sValidTypeNames[3] = {
   u"mark",
   u"measure",
   u"resource",
-  u"server"
 };
 
 void
 PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
                              ErrorResult& aRv)
 {
   if (aOptions.mEntryTypes.IsEmpty()) {
     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
--- a/dom/script/ScriptLoadHandler.cpp
+++ b/dom/script/ScriptLoadHandler.cpp
@@ -158,21 +158,16 @@ ScriptLoadHandler::EnsureDecoder(nsIIncr
   if (mDecoder) {
     return true;
   }
 
   nsAutoCString charset;
   if (!EnsureDecoder(aLoader, aData, aDataLength, aEndOfStream, charset)) {
     return false;
   }
-  if (charset.Length() == 0) {
-    charset = "?";
-  }
-  mozilla::Telemetry::Accumulate(mozilla::Telemetry::DOM_SCRIPT_SRC_ENCODING,
-    charset);
   return true;
 }
 
 bool
 ScriptLoadHandler::EnsureDecoder(nsIIncrementalStreamLoader* aLoader,
                                  const uint8_t* aData,
                                  uint32_t aDataLength,
                                  bool aEndOfStream,
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -188,72 +188,53 @@ ScriptLoader::~ScriptLoader()
   for (size_t i = 0; i < mPreloads.Length(); i++) {
     AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::NotUsed);
   }
 }
 
 // Collect telemtry data about the cache information, and the kind of source
 // which are being loaded, and where it is being loaded from.
 static void
-CollectScriptTelemetry(nsIIncrementalStreamLoader* aLoader,
-                       ScriptLoadRequest* aRequest)
+CollectScriptTelemetry(ScriptLoadRequest* aRequest)
 {
   using namespace mozilla::Telemetry;
 
   // Skip this function if we are not running telemetry.
   if (!CanRecordExtended()) {
     return;
   }
 
   // Report the script kind.
   if (aRequest->IsModuleRequest()) {
     AccumulateCategorical(LABELS_DOM_SCRIPT_KIND::ModuleScript);
   } else {
     AccumulateCategorical(LABELS_DOM_SCRIPT_KIND::ClassicScript);
   }
 
-  // Report the type of source, as well as the size of the source.
+  // Report the type of source. This is used to monitor the status of the
+  // JavaScript Start-up Bytecode Cache, with the expectation of an almost zero
+  // source-fallback and alternate-data being roughtly equal to source loads.
   if (aRequest->IsLoadingSource()) {
     if (aRequest->mIsInline) {
       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Inline);
       nsAutoString inlineData;
       aRequest->mElement->GetScriptText(inlineData);
-      Accumulate(DOM_SCRIPT_INLINE_SIZE, inlineData.Length());
     } else if (aRequest->IsTextSource()) {
       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::SourceFallback);
-      Accumulate(DOM_SCRIPT_SOURCE_SIZE, aRequest->ScriptText().length());
     }
     // TODO: Add telemetry for BinAST encoded source.
   } else {
     MOZ_ASSERT(aRequest->IsLoading());
     if (aRequest->IsTextSource()) {
       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Source);
-      Accumulate(DOM_SCRIPT_SOURCE_SIZE, aRequest->ScriptText().length());
     } else if (aRequest->IsBytecode()) {
       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::AltData);
-      Accumulate(DOM_SCRIPT_BYTECODE_SIZE, aRequest->mScriptBytecode.length());
     }
     // TODO: Add telemetry for BinAST encoded source.
   }
-
-  // Skip if we do not have any cache information for the given script.
-  if (!aLoader) {
-    return;
-  }
-  nsCOMPtr<nsIRequest> channel;
-  aLoader->GetRequest(getter_AddRefs(channel));
-  nsCOMPtr<nsICacheInfoChannel> cic(do_QueryInterface(channel));
-  if (!cic) {
-    return;
-  }
-
-  int32_t fetchCount = 0;
-  if (NS_SUCCEEDED(cic->GetCacheTokenFetchCount(&fetchCount))) {
-    Accumulate(DOM_SCRIPT_FETCH_COUNT, fetchCount);
-  }
 }
 
 // Helper method for checking if the script element is an event-handler
 // This means that it has both a for-attribute and a event-attribute.
 // Also, if the for-attribute has a value that matches "\s*window\s*",
 // and the event-attribute matches "\s*onload([ \(].*)?" then it isn't an
 // eventhandler. (both matches are case insensitive).
 // This is how IE seems to filter out a window's onload handler from a
@@ -1514,17 +1495,17 @@ ScriptLoader::ProcessInlineScript(nsIScr
                       SRIMetadata(), // SRI doesn't apply
                       mDocument->GetReferrerPolicy());
   request->mIsInline = true;
   request->mTriggeringPrincipal = mDocument->NodePrincipal();
   request->mLineNo = aElement->GetScriptLineNumber();
   request->mProgress = ScriptLoadRequest::Progress::eLoading_Source;
   request->SetTextSource();
   TRACE_FOR_TEST_BOOL(request->mElement, "scriptloader_load_source");
-  CollectScriptTelemetry(nullptr, request);
+  CollectScriptTelemetry(request);
 
   // Only the 'async' attribute is heeded on an inline module script and
   // inline classic scripts ignore both these attributes.
   MOZ_ASSERT(!aElement->GetScriptDeferred());
   MOZ_ASSERT_IF(!request->IsModuleRequest(), !aElement->GetScriptAsync());
   request->SetScriptMode(false, aElement->GetScriptAsync());
 
   LOG(("ScriptLoadRequest (%p): Created request for inline script",
@@ -2194,30 +2175,16 @@ ScriptLoader::ShouldCacheBytecode(Script
       return false;
     }
   }
 
   LOG(("ScriptLoadRequest (%p): Bytecode-cache: Trigger encoding.", aRequest));
   return true;
 }
 
-static bool
-ShouldRecordParseTimeTelemetry(ScriptLoadRequest* aRequest)
-{
-  static const size_t MinScriptChars = 1024;
-  static const size_t MinBinASTBytes = 700;
-
-  if (aRequest->IsTextSource()) {
-    return aRequest->ScriptText().length() >= MinScriptChars;
-  } else {
-    MOZ_ASSERT(aRequest->IsBinASTSource());
-    return aRequest->ScriptBinASTData().length() >= MinBinASTBytes;
-  }
-}
-
 nsresult
 ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
 {
   using namespace mozilla::Telemetry;
   MOZ_ASSERT(aRequest->IsReadyToRun());
 
   // We need a document to evaluate scripts.
   if (!mDocument) {
@@ -2226,19 +2193,16 @@ ScriptLoader::EvaluateScript(ScriptLoadR
 
   nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
   nsIDocument* ownerDoc = scriptContent->OwnerDoc();
   if (ownerDoc != mDocument) {
     // Willful violation of HTML5 as of 2010-12-01
     return NS_ERROR_FAILURE;
   }
 
-  // Report telemetry results of the number of scripts evaluated.
-  mDocument->SetDocumentIncCounter(IncCounter::eIncCounter_ScriptTag);
-
   // Get the script-type to be used by this element.
   NS_ASSERTION(scriptContent, "no content - what is default script-type?");
 
   nsCOMPtr<nsIScriptGlobalObject> globalObject = GetScriptGlobalObject();
   if (!globalObject) {
     return NS_ERROR_FAILURE;
   }
 
@@ -2313,80 +2277,58 @@ ScriptLoader::EvaluateScript(ScriptLoadR
       rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
 
       if (NS_SUCCEEDED(rv)) {
         if (aRequest->IsBytecode()) {
           TRACE_FOR_TEST(aRequest->mElement, "scriptloader_execute");
           nsJSUtils::ExecutionContext exec(cx, global);
           if (aRequest->mOffThreadToken) {
             LOG(("ScriptLoadRequest (%p): Decode Bytecode & Join and Execute", aRequest));
-            AutoTimer<DOM_SCRIPT_OFF_THREAD_DECODE_EXEC_MS> timer;
             rv = exec.DecodeJoinAndExec(&aRequest->mOffThreadToken);
           } else {
             LOG(("ScriptLoadRequest (%p): Decode Bytecode and Execute", aRequest));
-            AutoTimer<DOM_SCRIPT_MAIN_THREAD_DECODE_EXEC_MS> timer;
             rv = exec.DecodeAndExec(options, aRequest->mScriptBytecode,
                                     aRequest->mBytecodeOffset);
           }
           // We do not expect to be saving anything when we already have some
           // bytecode.
           MOZ_ASSERT(!aRequest->mCacheInfo);
         } else {
           MOZ_ASSERT(aRequest->IsSource());
           JS::Rooted<JSScript*> script(cx);
           bool encodeBytecode = ShouldCacheBytecode(aRequest);
 
-          TimeStamp start;
-          if (Telemetry::CanRecordExtended()) {
-            // Only record telemetry for scripts which are above a threshold.
-            if (aRequest->mCacheInfo && ShouldRecordParseTimeTelemetry(aRequest)) {
-                start = TimeStamp::Now();
-            }
-          }
-
           {
             nsJSUtils::ExecutionContext exec(cx, global);
             exec.SetEncodeBytecode(encodeBytecode);
             TRACE_FOR_TEST(aRequest->mElement, "scriptloader_execute");
             if (aRequest->mOffThreadToken) {
               // Off-main-thread parsing.
               LOG(("ScriptLoadRequest (%p): Join (off-thread parsing) and Execute",
                    aRequest));
               if (aRequest->IsBinASTSource()) {
                 rv = exec.DecodeBinASTJoinAndExec(&aRequest->mOffThreadToken, &script);
               } else {
                 MOZ_ASSERT(aRequest->IsTextSource());
                 rv = exec.JoinAndExec(&aRequest->mOffThreadToken, &script);
               }
-              if (start) {
-                AccumulateTimeDelta(encodeBytecode
-                                    ? DOM_SCRIPT_OFF_THREAD_PARSE_ENCODE_EXEC_MS
-                                    : DOM_SCRIPT_OFF_THREAD_PARSE_EXEC_MS,
-                                    start);
-              }
             } else {
               // Main thread parsing (inline and small scripts)
               LOG(("ScriptLoadRequest (%p): Compile And Exec", aRequest));
               if (aRequest->IsBinASTSource()) {
                 rv = exec.DecodeBinASTAndExec(options,
                                               aRequest->ScriptBinASTData().begin(),
                                               aRequest->ScriptBinASTData().length(),
                                               &script);
               } else {
                 MOZ_ASSERT(aRequest->IsTextSource());
                 nsAutoString inlineData;
                 SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
                 rv = exec.CompileAndExec(options, srcBuf, &script);
               }
-              if (start) {
-                AccumulateTimeDelta(encodeBytecode
-                                    ? DOM_SCRIPT_MAIN_THREAD_PARSE_ENCODE_EXEC_MS
-                                    : DOM_SCRIPT_MAIN_THREAD_PARSE_EXEC_MS,
-                                    start);
-              }
             }
           }
 
           // Queue the current script load request to later save the bytecode.
           if (script && encodeBytecode) {
             aRequest->mScript = script;
             HoldJSObjects(aRequest);
             TRACE_FOR_TEST(aRequest->mElement, "scriptloader_encode");
@@ -2494,17 +2436,16 @@ ScriptLoader::EncodeBytecode()
   }
 
   nsCOMPtr<nsIScriptContext> context = globalObject->GetScriptContext();
   if (!context) {
     GiveUpBytecodeEncoding();
     return;
   }
 
-  Telemetry::AutoTimer<Telemetry::DOM_SCRIPT_ENCODING_MS_PER_DOCUMENT> timer;
   AutoEntryScript aes(globalObject, "encode bytecode", true);
   RefPtr<ScriptLoadRequest> request;
   while (!mBytecodeEncodingQueue.isEmpty()) {
     request = mBytecodeEncodingQueue.StealFirst();
     EncodeRequestBytecode(aes.cx(), request);
     request->mScriptBytecode.clearAndFree();
     request->DropBytecodeCacheReferences();
   }
@@ -2519,63 +2460,55 @@ ScriptLoader::EncodeRequestBytecode(JSCo
   auto bytecodeFailed = mozilla::MakeScopeExit([&]() {
     TRACE_FOR_TEST_NONE(aRequest->mElement, "scriptloader_bytecode_failed");
   });
 
   JS::RootedScript script(aCx, aRequest->mScript);
   if (!JS::FinishIncrementalEncoding(aCx, script, aRequest->mScriptBytecode)) {
     LOG(("ScriptLoadRequest (%p): Cannot serialize bytecode",
          aRequest));
-    AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::EncodingFailure);
     return;
   }
 
   if (aRequest->mScriptBytecode.length() >= UINT32_MAX) {
     LOG(("ScriptLoadRequest (%p): Bytecode cache is too large to be decoded correctly.",
          aRequest));
-    AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::BufferTooLarge);
     return;
   }
 
   // Open the output stream to the cache entry alternate data storage. This
   // might fail if the stream is already open by another request, in which
   // case, we just ignore the current one.
   nsCOMPtr<nsIOutputStream> output;
   rv = aRequest->mCacheInfo->OpenAlternativeOutputStream(nsContentUtils::JSBytecodeMimeType(),
                                                          aRequest->mScriptBytecode.length(),
                                                          getter_AddRefs(output));
   if (NS_FAILED(rv)) {
     LOG(("ScriptLoadRequest (%p): Cannot open bytecode cache (rv = %X, output = %p)",
          aRequest, unsigned(rv), output.get()));
-    AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::OpenFailure);
     return;
   }
   MOZ_ASSERT(output);
   auto closeOutStream = mozilla::MakeScopeExit([&]() {
     nsresult rv = output->Close();
     LOG(("ScriptLoadRequest (%p): Closing (rv = %X)",
          aRequest, unsigned(rv)));
-    if (NS_FAILED(rv)) {
-      AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::CloseFailure);
-    }
   });
 
   uint32_t n;
   rv = output->Write(reinterpret_cast<char*>(aRequest->mScriptBytecode.begin()),
                      aRequest->mScriptBytecode.length(), &n);
   LOG(("ScriptLoadRequest (%p): Write bytecode cache (rv = %X, length = %u, written = %u)",
        aRequest, unsigned(rv), unsigned(aRequest->mScriptBytecode.length()), n));
   if (NS_FAILED(rv)) {
-    AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::WriteFailure);
     return;
   }
 
   bytecodeFailed.release();
   TRACE_FOR_TEST_NONE(aRequest->mElement, "scriptloader_bytecode_saved");
-  AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::EncodingSuccess);
 }
 
 void
 ScriptLoader::GiveUpBytecodeEncoding()
 {
   // If the document went away prematurely, we still want to set this, in order
   // to avoid queuing more scripts.
   mGiveUpEncoding = true;
@@ -2811,20 +2744,16 @@ ScriptLoader::ConvertToUTF16(nsIChannel*
   Tie(result, read, written, hadErrors) = unicodeDecoder->DecodeToUTF16(
     data, MakeSpan(aBufOut, unicodeLength.value()), true);
   MOZ_ASSERT(result == kInputEmpty);
   MOZ_ASSERT(read == aLength);
   MOZ_ASSERT(written <= unicodeLength.value());
   Unused << hadErrors;
   aLengthOut = written;
 
-  nsAutoCString charset;
-  unicodeDecoder->Encoding()->Name(charset);
-  mozilla::Telemetry::Accumulate(mozilla::Telemetry::DOM_SCRIPT_SRC_ENCODING,
-    charset);
   return NS_OK;
 }
 
 nsresult
 ScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
                                ScriptLoadRequest* aRequest,
                                nsresult aChannelStatus,
                                nsresult aSRIStatus,
@@ -3130,17 +3059,17 @@ ScriptLoader::PrepareLoadedRequest(Scrip
   if (NS_FAILED(aStatus)) {
     return aStatus;
   }
 
   if (aRequest->IsCanceled()) {
     return NS_BINDING_ABORTED;
   }
   MOZ_ASSERT(aRequest->IsLoading());
-  CollectScriptTelemetry(aLoader, aRequest);
+  CollectScriptTelemetry(aRequest);
 
   // If we don't have a document, then we need to abort further
   // evaluation.
   if (!mDocument) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // If the load returned an error page, then we need to abort
--- a/dom/serviceworkers/ServiceWorkerManager.cpp
+++ b/dom/serviceworkers/ServiceWorkerManager.cpp
@@ -307,17 +307,17 @@ ServiceWorkerManager::Init(ServiceWorker
 
   mActor = static_cast<ServiceWorkerManagerChild*>(actor);
 }
 
 RefPtr<GenericPromise>
 ServiceWorkerManager::StartControllingClient(const ClientInfo& aClientInfo,
                                              ServiceWorkerRegistrationInfo* aRegistrationInfo)
 {
-  MOZ_DIAGNOSTIC_ASSERT(aRegistrationInfo->GetActive());
+  MOZ_RELEASE_ASSERT(aRegistrationInfo->GetActive());
 
   RefPtr<GenericPromise> ref;
 
   const ServiceWorkerDescriptor& active =
     aRegistrationInfo->GetActive()->Descriptor();
 
   auto entry = mControlledClients.LookupForAdd(aClientInfo.Id());
   if (entry) {
@@ -1877,16 +1877,17 @@ ServiceWorkerManager::StartControlling(c
   nsCOMPtr<nsIURI> scope;
   nsresult rv =
     NS_NewURI(getter_AddRefs(scope), aServiceWorker.Scope(), nullptr, nullptr);
   NS_ENSURE_SUCCESS(rv, false);
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetServiceWorkerRegistrationInfo(principal, scope);
   NS_ENSURE_TRUE(registration, false);
+  NS_ENSURE_TRUE(registration->GetActive(), false);
 
   StartControllingClient(aClientInfo, registration);
 
   return true;
 }
 
 void
 ServiceWorkerManager::MaybeCheckNavigationUpdate(const ClientInfo& aClientInfo)
@@ -2552,20 +2553,25 @@ ServiceWorkerManager::UpdateInternal(nsI
   queue->ScheduleJob(job);
 }
 
 already_AddRefed<GenericPromise>
 ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument,
                                        ServiceWorkerRegistrationInfo* aWorkerRegistration)
 {
   MOZ_DIAGNOSTIC_ASSERT(aWorkerRegistration);
-  MOZ_DIAGNOSTIC_ASSERT(aWorkerRegistration->GetActive());
 
   RefPtr<GenericPromise> ref;
 
+  if (!aWorkerRegistration->GetActive()) {
+    ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+                                          __func__);
+    return ref.forget();
+  }
+
   // Same origin check
   if (!aWorkerRegistration->Principal()->Equals(aDocument->NodePrincipal())) {
     ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_SECURITY_ERR, __func__);
     return ref.forget();
   }
 
   Maybe<ClientInfo> clientInfo(aDocument->GetClientInfo());
   if (NS_WARN_IF(clientInfo.isNothing())) {
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -223,8 +223,11 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_
     LOCAL_INCLUDES += [
         '/security/sandbox/chromium',
         '/security/sandbox/chromium-shim',
         '/security/sandbox/win/src/sandboxbroker',
     ]
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-shadow']
+
+if CONFIG['NIGHTLY_BUILD']:
+    DEFINES['ASYNC_CONTENTPROC_LAUNCH'] = True
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -337,28 +337,16 @@ class JS_FRIEND_API(GCCellPtr)
 
     bool mayBeOwnedByOtherRuntimeSlow() const;
 
     JS::TraceKind outOfLineKind() const;
 
     uintptr_t ptr;
 };
 
-inline bool
-operator==(const GCCellPtr& ptr1, const GCCellPtr& ptr2)
-{
-    return ptr1.asCell() == ptr2.asCell();
-}
-
-inline bool
-operator!=(const GCCellPtr& ptr1, const GCCellPtr& ptr2)
-{
-    return !(ptr1 == ptr2);
-}
-
 // Unwraps the given GCCellPtr and calls the given functor with a template
 // argument of the actual type of the pointer.
 template <typename F, typename... Args>
 auto
 DispatchTyped(F f, GCCellPtr thing, Args&&... args)
   -> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
 {
     switch (thing.kind()) {
@@ -369,16 +357,31 @@ DispatchTyped(F f, GCCellPtr thing, Args
 #undef JS_EXPAND_DEF
       default:
           MOZ_CRASH("Invalid trace kind in DispatchTyped for GCCellPtr.");
     }
 }
 
 } /* namespace JS */
 
+// These are defined in the toplevel namespace instead of within JS so that
+// they won't shadow other operator== overloads (see bug 1456512.)
+
+inline bool
+operator==(const JS::GCCellPtr& ptr1, const JS::GCCellPtr& ptr2)
+{
+    return ptr1.asCell() == ptr2.asCell();
+}
+
+inline bool
+operator!=(const JS::GCCellPtr& ptr1, const JS::GCCellPtr& ptr2)
+{
+    return !(ptr1 == ptr2);
+}
+
 namespace js {
 namespace gc {
 namespace detail {
 
 static MOZ_ALWAYS_INLINE uintptr_t*
 GetGCThingMarkBitmap(const uintptr_t addr)
 {
     // Note: the JIT pre-barrier trampolines inline this code. Update that
--- a/js/src/gc/Cell.h
+++ b/js/src/gc/Cell.h
@@ -388,17 +388,17 @@ TenuredCell::readBarrier(TenuredCell* th
         Cell* tmp = thing;
         TraceManuallyBarrieredGenericPointerEdge(shadowZone->barrierTracer(), &tmp, "read barrier");
         MOZ_ASSERT(tmp == thing);
     }
 
     if (thing->isMarkedGray()) {
         // There shouldn't be anything marked grey unless we're on the main thread.
         MOZ_ASSERT(CurrentThreadCanAccessRuntime(thing->runtimeFromAnyThread()));
-        if (!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone))
+        if (!JS::CurrentThreadIsHeapCollecting())
             JS::UnmarkGrayGCThingRecursively(JS::GCCellPtr(thing, thing->getTraceKind()));
     }
 }
 
 void
 AssertSafeToSkipBarrier(TenuredCell* thing);
 
 /* static */ MOZ_ALWAYS_INLINE void
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -5003,17 +5003,16 @@ GCRuntime::groupZonesForSweeping(JS::gcr
     JSContext* cx = rt->mainContextFromOwnThread();
     Zone* maybeAtomsZone = atomsZone->wasGCStarted() ? atomsZone.ref() : nullptr;
     ZoneComponentFinder finder(cx->nativeStackLimit[JS::StackForSystemCode], maybeAtomsZone);
     if (!isIncremental || !findInterZoneEdges())
         finder.useOneComponent();
 
 #ifdef JS_GC_ZEAL
     // Use one component for two-slice zeal modes.
-    MOZ_ASSERT_IF(useZeal, isIncremental);
     if (useZeal && hasIncrementalTwoSliceZealMode())
         finder.useOneComponent();
 #endif
 
     for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
         MOZ_ASSERT(zone->isGCMarking());
         finder.addNode(zone);
     }
@@ -5756,18 +5755,17 @@ GCRuntime::beginSweepingSweepGroup(FreeO
     return Finished;
 }
 
 #ifdef JS_GC_ZEAL
 
 bool
 GCRuntime::shouldYieldForZeal(ZealMode mode)
 {
-    MOZ_ASSERT_IF(useZeal, isIncremental);
-    return useZeal && hasZealMode(mode);
+    return useZeal && isIncremental && hasZealMode(mode);
 }
 
 IncrementalProgress
 GCRuntime::maybeYieldForSweepingZeal(FreeOp* fop, SliceBudget& budget)
 {
     /*
      * Check whether we need to yield for GC zeal. We always yield when running
      * in incremental multi-slice zeal mode so RunDebugGC can reset the slice
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1462337.js
@@ -0,0 +1,10 @@
+if (!('oomTest' in this))
+    quit();
+
+oomTest(function() {
+    grayRoot().x = Object.create((obj[name]++));
+});
+oomTest(function() {
+    gczeal(9);
+    gcslice(new.target);
+});
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3571,16 +3571,17 @@ WorkerMain(void* arg)
         return;
 
     ShellContext* sc = js_new<ShellContext>(cx);
     if (!sc)
         return;
 
     auto guard = mozilla::MakeScopeExit([&] {
         CancelOffThreadJobsForContext(cx);
+        sc->markObservers.reset();
         JS_DestroyContext(cx);
         js_delete(sc);
         js_delete(input);
     });
 
     sc->isWorker = true;
     JS_SetContextPrivate(cx, sc);
     SetWorkerContextOptions(cx);
@@ -8555,21 +8556,16 @@ SetContextOptions(JSContext* cx, const O
                    strcmp(str, "pessimistic") != 0)
         {
             // We accept "pessimistic" and "optimistic" as synonyms for "on"
             // for backwards compatibility.
             return OptionFailure("ion-gvn", str);
         }
     }
 
-    if (op.getStringOption("ion-aa")) {
-        // Removed in bug 1455280, the option is preserved
-        // to ease transition for fuzzers and other tools
-    }
-
     if (const char* str = op.getStringOption("ion-licm")) {
         if (strcmp(str, "on") == 0)
             jit::JitOptions.disableLicm = false;
         else if (strcmp(str, "off") == 0)
             jit::JitOptions.disableLicm = true;
         else
             return OptionFailure("ion-licm", str);
     }
@@ -9065,19 +9061,16 @@ main(int argc, char** argv, char** envp)
         || !op.addStringOption('\0', "ion-scalar-replacement", "on/off",
                                "Scalar Replacement (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-gvn", "[mode]",
                                "Specify Ion global value numbering:\n"
                                "  off: disable GVN\n"
                                "  on:  enable GVN (default)\n")
         || !op.addStringOption('\0', "ion-licm", "on/off",
                                "Loop invariant code motion (default: on, off to disable)")
-        || !op.addStringOption('\0', "ion-aa", "flow-sensitive/flow-insensitive",
-                               "Specify wheter or not to use flow sensitive Alias Analysis"
-                               "(default: flow-insensitive)")
         || !op.addStringOption('\0', "ion-edgecase-analysis", "on/off",
                                "Find edge cases where Ion can avoid bailouts (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-pgo", "on/off",
                                "Profile guided optimization (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-range-analysis", "on/off",
                                "Range analysis (default: on, off to disable)")
 #if defined(__APPLE__)
         || !op.addStringOption('\0', "ion-sincos", "on/off",
new file mode 100644
--- /dev/null
+++ b/js/src/tests/non262/regress/regress-1456512-greyreadbarrier.js
@@ -0,0 +1,7 @@
+var wm = new WeakMap();
+grayRoot().map = wm;
+wm = null;
+gczeal(13, 7);
+var lfOffThreadGlobal = newGlobal();
+
+reportCompare('do not crash', 'do not crash', 'did not crash!');
new file mode 100644
--- /dev/null
+++ b/js/src/tests/non262/regress/regress-1456518-workergray.js
@@ -0,0 +1,7 @@
+if (typeof 'evalInWorder' == 'function') {
+    evalInWorker(`
+  addMarkObservers([grayRoot(), grayRoot().x, this, Object.create(null)]);
+`);
+}
+
+reportCompare('do not crash', 'do not crash', 'did not crash!');
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -302,48 +302,47 @@ JSRope::copyTwoByteChars(JSContext* cx, 
     return copyCharsInternal<char16_t>(cx, out, false);
 }
 
 template <typename CharT>
 bool
 JSRope::copyCharsInternal(JSContext* cx, ScopedJSFreePtr<CharT>& out,
                           bool nullTerminate) const
 {
-    /*
-     * Perform non-destructive post-order traversal of the rope, splatting
-     * each node's characters into a contiguous buffer.
-     */
+    // Left-leaning ropes are far more common than right-leaning ropes, so
+    // perform a non-destructive traversal of the rope, right node first,
+    // splatting each node's characters into a contiguous buffer.
 
     size_t n = length();
     if (cx)
         out.reset(cx->pod_malloc<CharT>(n + 1));
     else
         out.reset(js_pod_malloc<CharT>(n + 1));
 
     if (!out)
         return false;
 
     Vector<const JSString*, 8, SystemAllocPolicy> nodeStack;
     const JSString* str = this;
-    CharT* pos = out;
+    CharT* end = out + str->length();
     while (true) {
         if (str->isRope()) {
-            if (!nodeStack.append(str->asRope().rightChild()))
+            if (!nodeStack.append(str->asRope().leftChild()))
                 return false;
-            str = str->asRope().leftChild();
+            str = str->asRope().rightChild();
         } else {
-            CopyChars(pos, str->asLinear());
-            pos += str->length();
+            end -= str->length();
+            CopyChars(end, str->asLinear());
             if (nodeStack.empty())
                 break;
             str = nodeStack.popCopy();
         }
     }
 
-    MOZ_ASSERT(pos == out + n);
+    MOZ_ASSERT(end == out);
 
     if (nullTerminate)
         out[n] = 0;
 
     return true;
 }
 
 #ifdef DEBUG
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -82,39 +82,33 @@ var supported_properties = {
     "-moz-image-region": [ test_rect_transition ],
     "-moz-outline-radius-bottomleft": [ test_radius_transition ],
     "-moz-outline-radius-bottomright": [ test_radius_transition ],
     "-moz-outline-radius-topleft": [ test_radius_transition ],
     "-moz-outline-radius-topright": [ test_radius_transition ],
     "background-color": [ test_color_transition,
                           test_true_currentcolor_transition ],
     "background-position": [ test_background_position_transition,
-                             // FIXME: We don't currently test clamping,
-                             // since background-position uses calc() as
-                             // an intermediate form.
-                             /* test_length_percent_pair_unclamped */ ],
+                             test_length_percent_pair_unclamped ],
     "background-position-x": [ test_background_position_coord_transition,
                                test_length_transition,
                                test_percent_transition,
                              // FIXME: We don't currently test clamping,
                              // since background-position-x uses calc() as
                              // an intermediate form.
                              /* test_length_percent_pair_unclamped */ ],
     "background-position-y": [ test_background_position_coord_transition,
                                test_length_transition,
                                test_percent_transition,
                              // FIXME: We don't currently test clamping,
                              // since background-position-y uses calc() as
                              // an intermediate form.
                              /* test_length_percent_pair_unclamped */ ],
     "background-size": [ test_background_size_transition,
-                         // FIXME: We don't currently test clamping,
-                         // since background-size uses calc() as an
-                         // intermediate form.
-                         /* test_length_percent_pair_clamped */ ],
+                         test_length_percent_pair_clamped ],
     "border-bottom-color": [ test_color_transition,
                              test_true_currentcolor_transition ],
     "border-bottom-width": [ test_length_transition,
                              test_length_clamped ],
     "border-left-color": [ test_color_transition,
                            test_true_currentcolor_transition ],
     "border-left-width": [ test_length_transition,
                            test_length_clamped ],
@@ -190,39 +184,33 @@ var supported_properties = {
                      test_length_unclamped, test_percent_unclamped ],
     "margin-right": [ test_length_transition, test_percent_transition,
                       test_length_percent_calc_transition,
                       test_length_unclamped, test_percent_unclamped ],
     "margin-top": [ test_length_transition, test_percent_transition,
                     test_length_percent_calc_transition,
                     test_length_unclamped, test_percent_unclamped ],
     "mask-position": [ test_background_position_transition,
-                       // FIXME: We don't currently test clamping,
-                       // since mask-position uses calc() as
-                       // an intermediate form.
-                       /* test_length_percent_pair_unclamped */ ],
+                       test_length_percent_pair_unclamped ],
     "mask-position-x": [ test_background_position_coord_transition,
                          test_length_transition,
                          test_percent_transition,
                          // FIXME: We don't currently test clamping,
                          // since background-position-x uses calc() as
                          // an intermediate form.
                          /* test_length_percent_pair_unclamped */ ],
     "mask-position-y": [ test_background_position_coord_transition,
                          test_length_transition,
                          test_percent_transition,
                          // FIXME: We don't currently test clamping,
                          // since background-position-y uses calc() as
                          // an intermediate form.
                          /* test_length_percent_pair_unclamped */ ],
     "mask-size": [ test_background_size_transition,
-                   // FIXME: We don't currently test clamping,
-                   // since mask-size uses calc() as an
-                   // intermediate form.
-                   /* test_length_percent_pair_clamped */ ],
+                   test_length_percent_pair_clamped ],
     "max-height": [ test_length_transition, test_percent_transition,
                     test_length_clamped, test_percent_clamped ],
     "max-width": [ test_length_transition, test_percent_transition,
                    test_length_clamped, test_percent_clamped ],
     "min-height": [ test_length_transition, test_percent_transition,
                     test_length_clamped, test_percent_clamped ],
     "min-width": [ test_length_transition, test_percent_transition,
                    test_length_clamped, test_percent_clamped ],
@@ -2114,21 +2102,28 @@ function test_length_percent_pair_clampe
 function test_length_percent_pair_unclamped(prop) {
   test_length_percent_pair_clamped_or_unclamped(prop, false);
 }
 
 function test_length_percent_pair_clamped_or_unclamped(prop, is_clamped) {
   div.style.setProperty("transition-timing-function", FUNC_NEGATIVE, "");
   div.style.setProperty("transition-property", "none", "");
   div.style.setProperty(prop, "0px 0%", "");
-  is(cs.getPropertyValue(prop), "0px 0px",
+  var is_zero = function(val) {
+    if (prop == "transform-origin" || prop == "perspective-origin") {
+      // These two properties resolve percentages to pixels.
+      return val == "0px 0px";
+    }
+    return val == "0px 0%";
+  }
+  ok(is_zero(cs.getPropertyValue(prop)),
      "length+percent-valued property " + prop + ": flush before clamping test");
   div.style.setProperty("transition-property", prop, "");
   div.style.setProperty(prop, "30px 25%", "");
-  (is_clamped ? is : isnot)(cs.getPropertyValue(prop), "0px 0px",
+  is(is_zero(cs.getPropertyValue(prop)), is_clamped,
      "length+percent-valued property " + prop + ": clamping of negatives");
   div.style.setProperty("transition-timing-function", "linear", "");
 }
 
 function test_rect_transition(prop) {
   div.style.setProperty("transition-property", "none", "");
   div.style.setProperty(prop, "rect(4px, 16px, 12px, 6px)", "");
   is(cs.getPropertyValue(prop), "rect(4px, 16px, 12px, 6px)",
--- a/mfbt/Maybe.h
+++ b/mfbt/Maybe.h
@@ -310,21 +310,17 @@ public:
   }
 
   /* Methods that check whether this Maybe contains a value */
   explicit operator bool() const { return isSome(); }
   bool isSome() const { return mIsSome; }
   bool isNothing() const { return !mIsSome; }
 
   /* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|. */
-  T value() const
-  {
-    MOZ_ASSERT(mIsSome);
-    return ref();
-  }
+  T value() const;
 
   /*
    * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
    * the default value provided.
    */
   template<typename V>
   T valueOr(V&& aDefault) const
   {
@@ -343,27 +339,18 @@ public:
   {
     if (isSome()) {
       return ref();
     }
     return aFunc();
   }
 
   /* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|. */
-  T* ptr()
-  {
-    MOZ_ASSERT(mIsSome);
-    return &ref();
-  }
-
-  const T* ptr() const
-  {
-    MOZ_ASSERT(mIsSome);
-    return &ref();
-  }
+  T* ptr();
+  const T* ptr() const;
 
   /*
    * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
    * returns the default value provided.
    */
   T* ptrOr(T* aDefault)
   {
     if (isSome()) {
@@ -397,40 +384,22 @@ public:
   const T* ptrOrFrom(F&& aFunc) const
   {
     if (isSome()) {
       return ptr();
     }
     return aFunc();
   }
 
-  T* operator->()
-  {
-    MOZ_ASSERT(mIsSome);
-    return ptr();
-  }
-
-  const T* operator->() const
-  {
-    MOZ_ASSERT(mIsSome);
-    return ptr();
-  }
+  T* operator->();
+  const T* operator->() const;
 
   /* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
-  T& ref()
-  {
-    MOZ_ASSERT(mIsSome);
-    return *static_cast<T*>(data());
-  }
-
-  const T& ref() const
-  {
-    MOZ_ASSERT(mIsSome);
-    return *static_cast<const T*>(data());
-  }
+  T& ref();
+  const T& ref() const;
 
   /*
    * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
    * the default value provided.
    */
   T& refOr(T& aDefault)
   {
     if (isSome()) {
@@ -464,27 +433,18 @@ public:
   const T& refOrFrom(F&& aFunc) const
   {
     if (isSome()) {
       return ref();
     }
     return aFunc();
   }
 
-  T& operator*()
-  {
-    MOZ_ASSERT(mIsSome);
-    return ref();
-  }
-
-  const T& operator*() const
-  {
-    MOZ_ASSERT(mIsSome);
-    return ref();
-  }
+  T& operator*();
+  const T& operator*() const;
 
   /* If |isSome()|, runs the provided function or functor on the contents of
    * this Maybe. */
   template<typename Func>
   Maybe& apply(Func aFunc)
   {
     if (isSome()) {
       aFunc(ref());
@@ -539,35 +499,112 @@ public:
     }
   }
 
   /*
    * Constructs a T value in-place in this empty Maybe<T>'s storage. The
    * arguments to |emplace()| are the parameters to T's constructor.
    */
   template<typename... Args>
-  void emplace(Args&&... aArgs)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (KnownNotNull, data()) T(Forward<Args>(aArgs)...);
-    mIsSome = true;
-  }
+  void emplace(Args&&... aArgs);
 
   friend std::ostream&
   operator<<(std::ostream& aStream, const Maybe<T>& aMaybe)
   {
     if (aMaybe) {
       aStream << aMaybe.ref();
     } else {
       aStream << "<Nothing>";
     }
     return aStream;
   }
 };
 
+template<typename T>
+T
+Maybe<T>::value() const
+{
+  MOZ_DIAGNOSTIC_ASSERT(mIsSome);
+  return ref();
+}
+
+template<typename T>
+T*
+Maybe<T>::ptr()
+{
+  MOZ_DIAGNOSTIC_ASSERT(mIsSome);
+  return &ref();
+}
+
+template<typename T>
+const T*
+Maybe<T>::ptr() const
+{
+  MOZ_DIAGNOSTIC_ASSERT(mIsSome);
+  return &ref();
+}
+
+template<typename T>
+T*
+Maybe<T>::operator->()
+{
+  MOZ_DIAGNOSTIC_ASSERT(mIsSome);
+  return ptr();
+}
+
+template<typename T>
+const T*
+Maybe<T>::operator->() const
+{
+  MOZ_DIAGNOSTIC_ASSERT(mIsSome);
+  return ptr();
+}
+
+template<typename T>
+T&
+Maybe<T>::ref()
+{
+  MOZ_DIAGNOSTIC_ASSERT(mIsSome);
+  return *static_cast<T*>(data());
+}
+
+template<typename T>
+const T&
+Maybe<T>::ref() const
+{
+  MOZ_DIAGNOSTIC_ASSERT(mIsSome);
+  return *static_cast<const T*>(data());
+}
+
+template<typename T>
+T&
+Maybe<T>::operator*()
+{
+  MOZ_DIAGNOSTIC_ASSERT(mIsSome);
+  return ref();
+}
+
+template<typename T>
+const T&
+Maybe<T>::operator*() const
+{
+  MOZ_DIAGNOSTIC_ASSERT(mIsSome);
+  return ref();
+}
+
+template<typename T>
+template<typename... Args>
+void
+Maybe<T>::emplace(Args&&... aArgs)
+{
+  MOZ_DIAGNOSTIC_ASSERT(!mIsSome);
+  ::new (KnownNotNull, data()) T(Forward<Args>(aArgs)...);
+  mIsSome = true;
+}
+
 /*
  * Some() creates a Maybe<T> value containing the provided T value. If T has a
  * move constructor, it's used to make this as efficient as possible.
  *
  * Some() selects the type of Maybe it returns by removing any const, volatile,
  * or reference qualifiers from the type of the value you pass to it. This gives
  * it more intuitive behavior when used in expressions, but it also means that
  * if you need to construct a Maybe value that holds a const, volatile, or
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -1852,16 +1852,36 @@ HttpChannelParent::StartRedirect(uint32_
       // Note, InterceptedHttpChannel can also do an internal redirect
       // for opaque response interception.  This should not actually
       // happen here in e10s mode.
       nsCOMPtr<nsIInterceptedChannel> oldIntercepted =
         do_QueryInterface(static_cast<nsIChannel*>(mChannel.get()));
       MOZ_ASSERT(!oldIntercepted);
 #endif
 
+      // We need to move across the reserved and initial client information
+      // to the new channel.  Normally this would be handled by the child
+      // ClientChannelHelper, but that is not notified of this redirect since
+      // we're not propagating it back to the child process.
+      nsCOMPtr<nsILoadInfo> oldLoadInfo;
+      Unused << mChannel->GetLoadInfo(getter_AddRefs(oldLoadInfo));
+      nsCOMPtr<nsILoadInfo> newLoadInfo;
+      Unused << newChannel->GetLoadInfo(getter_AddRefs(newLoadInfo));
+      if (oldLoadInfo && newLoadInfo) {
+        Maybe<ClientInfo> reservedClientInfo(oldLoadInfo->GetReservedClientInfo());
+        if (reservedClientInfo.isSome()) {
+          newLoadInfo->SetReservedClientInfo(reservedClientInfo.ref());
+        }
+
+        Maybe<ClientInfo> initialClientInfo(oldLoadInfo->GetInitialClientInfo());
+        if (initialClientInfo.isSome()) {
+          newLoadInfo->SetInitialClientInfo(initialClientInfo.ref());
+        }
+      }
+
       // Re-link the HttpChannelParent to the new InterceptedHttpChannel.
       nsCOMPtr<nsIChannel> linkedChannel;
       rv = NS_LinkRedirectChannels(registrarId, this, getter_AddRefs(linkedChannel));
       NS_ENSURE_SUCCESS(rv, rv);
       MOZ_ASSERT(linkedChannel == newChannel);
 
       // We immediately store the InterceptedHttpChannel as our nested
       // mChannel.  None of the redirect IPC messaging takes place.
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -159,17 +159,17 @@ def parse_property_aliases(alias_list):
 class Longhand(object):
     def __init__(self, style_struct, name, spec=None, animation_value_type=None, keyword=None,
                  predefined_type=None, servo_pref=None, gecko_pref=None,
                  enabled_in="content", need_index=False,
                  gecko_ffi_name=None,
                  allowed_in_keyframe_block=True, cast_type='u8',
                  logical=False, alias=None, extra_prefixes=None, boxed=False,
                  flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=False,
-                 vector=False, need_animatable=False, servo_restyle_damage="repaint"):
+                 vector=False, servo_restyle_damage="repaint"):
         self.name = name
         if not spec:
             raise TypeError("Spec should be specified for %s" % name)
         self.spec = spec
         self.keyword = keyword
         self.predefined_type = predefined_type
         self.ident = to_rust_ident(name)
         self.camel_case = to_camel_case(self.ident)
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -2602,28 +2602,34 @@ fn static_assert() {
     pub fn clone_font_weight(&self) -> longhands::font_weight::computed_value::T {
         let weight: f32 = unsafe {
             bindings::Gecko_FontWeight_ToFloat(self.gecko.mFont.weight)
         };
         longhands::font_weight::computed_value::T(weight)
     }
 
     pub fn set_font_stretch(&mut self, v: longhands::font_stretch::computed_value::T) {
-        unsafe { bindings::Gecko_FontStretch_SetFloat(&mut self.gecko.mFont.stretch, (v.0).0) };
+        unsafe {
+            bindings::Gecko_FontStretch_SetFloat(
+                &mut self.gecko.mFont.stretch,
+                v.value(),
+            )
+        };
     }
     ${impl_simple_copy('font_stretch', 'mFont.stretch')}
     pub fn clone_font_stretch(&self) -> longhands::font_stretch::computed_value::T {
+        use values::computed::font::FontStretch;
         use values::computed::Percentage;
         use values::generics::NonNegative;
 
         let stretch =
             unsafe { bindings::Gecko_FontStretch_ToFloat(self.gecko.mFont.stretch) };
         debug_assert!(stretch >= 0.);
 
-        NonNegative(Percentage(stretch))
+        FontStretch(NonNegative(Percentage(stretch)))
     }
 
     pub fn set_font_style(&mut self, v: longhands::font_style::computed_value::T) {
         use values::generics::font::FontStyle;
         let s = &mut self.gecko.mFont.style;
         unsafe {
             match v {
                 FontStyle::Normal => bindings::Gecko_FontSlantStyle_SetNormal(s),
@@ -3237,17 +3243,17 @@ fn static_assert() {
     }
 
     pub fn reset_scroll_snap_coordinate(&mut self, other: &Self) {
         self.copy_scroll_snap_coordinate_from(other)
     }
 
     pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T {
         let vec = self.gecko.mScrollSnapCoordinate.iter().map(|f| f.into()).collect();
-        longhands::scroll_snap_coordinate::computed_value::T(vec)
+        longhands::scroll_snap_coordinate::computed_value::List(vec)
     }
 
     ${impl_css_url('_moz_binding', 'mBinding')}
 
     ${impl_transition_time_value('delay', 'Delay')}
     ${impl_transition_time_value('duration', 'Duration')}
     ${impl_transition_timing_function()}
 
@@ -3743,18 +3749,19 @@ fn static_assert() {
         style_struct = next(x for x in data.style_structs if x.name == struct_name)
         longhand = next(x for x in style_struct.longhands if x.ident == ident)
         keyword = longhand.keyword
     %>
 
     <% copy_simple_image_array_property(name, shorthand, layer_field_name, field_name) %>
 
     pub fn set_${ident}<I>(&mut self, v: I)
-        where I: IntoIterator<Item=longhands::${ident}::computed_value::single_value::T>,
-              I::IntoIter: ExactSizeIterator
+    where
+        I: IntoIterator<Item=longhands::${ident}::computed_value::single_value::T>,
+        I::IntoIter: ExactSizeIterator,
     {
         use properties::longhands::${ident}::single_value::computed_value::T as Keyword;
         use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
 
         let v = v.into_iter();
 
         unsafe {
           Gecko_EnsureImageLayersLength(&mut self.gecko.${layer_field_name}, v.len(),
@@ -3779,17 +3786,17 @@ fn static_assert() {
 
         % if keyword.needs_cast():
         % for value in keyword.values_for('gecko'):
         const ${keyword.casted_constant_name(value, "u8")} : u8 =
             structs::${keyword.gecko_constant(value)} as u8;
         % endfor
         % endif
 
-        longhands::${ident}::computed_value::T (
+        longhands::${ident}::computed_value::List(
             self.gecko.${layer_field_name}.mLayers.iter()
                 .take(self.gecko.${layer_field_name}.${field_name}Count as usize)
                 .map(|ref layer| {
                     match layer.${field_name} {
                         % for value in longhand.keyword.values_for("gecko"):
                         % if keyword.needs_cast():
                         ${keyword.casted_constant_name(value, "u8")}
                         % else:
@@ -3846,17 +3853,17 @@ fn static_assert() {
                 StyleImageLayerRepeat::Repeat => BackgroundRepeatKeyword::Repeat,
                 StyleImageLayerRepeat::Space => BackgroundRepeatKeyword::Space,
                 StyleImageLayerRepeat::Round => BackgroundRepeatKeyword::Round,
                 StyleImageLayerRepeat::NoRepeat => BackgroundRepeatKeyword::NoRepeat,
                 _ => panic!("Found unexpected value in style struct for ${shorthand}_repeat property"),
             }
         }
 
-        longhands::${shorthand}_repeat::computed_value::T (
+        longhands::${shorthand}_repeat::computed_value::List(
             self.gecko.${image_layers_field}.mLayers.iter()
                 .take(self.gecko.${image_layers_field}.mRepeatCount as usize)
                 .map(|ref layer| {
                     T(to_servo(layer.mRepeat.mXRepeat), to_servo(layer.mRepeat.mYRepeat))
                 }).collect()
         )
     }
 
@@ -3885,17 +3892,17 @@ fn static_assert() {
     }
 
     pub fn reset_${shorthand}_position_${orientation}(&mut self, other: &Self) {
         self.copy_${shorthand}_position_${orientation}_from(other)
     }
 
     pub fn clone_${shorthand}_position_${orientation}(&self)
         -> longhands::${shorthand}_position_${orientation}::computed_value::T {
-        longhands::${shorthand}_position_${orientation}::computed_value::T(
+        longhands::${shorthand}_position_${orientation}::computed_value::List(
             self.gecko.${image_layers_field}.mLayers.iter()
                 .take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize)
                 .map(|position| position.mPosition.m${orientation.upper()}Position.into())
                 .collect()
         )
     }
 
     pub fn set_${shorthand}_position_${orientation[0]}<I>(&mut self,
@@ -3929,21 +3936,21 @@ fn static_assert() {
 
         let mut width = nsStyleCoord_CalcValue::new();
         let mut height = nsStyleCoord_CalcValue::new();
 
         let (w_type, h_type) = match servo {
             BackgroundSize::Explicit { width: explicit_width, height: explicit_height } => {
                 let mut w_type = nsStyleImageLayers_Size_DimensionType::eAuto;
                 let mut h_type = nsStyleImageLayers_Size_DimensionType::eAuto;
-                if let Some(w) = explicit_width.to_calc_value() {
+                if let Some(w) = explicit_width.0.to_calc_value() {
                     width = w;
                     w_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
                 }
-                if let Some(h) = explicit_height.to_calc_value() {
+                if let Some(h) = explicit_height.0.to_calc_value() {
                     height = h;
                     h_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
                 }
                 (w_type, h_type)
             }
             BackgroundSize::Cover => {
                 (
                     nsStyleImageLayers_Size_DimensionType::eCover,
@@ -3961,32 +3968,33 @@ fn static_assert() {
         nsStyleImageLayers_Size {
             mWidth: nsStyleImageLayers_Size_Dimension { _base: width },
             mHeight: nsStyleImageLayers_Size_Dimension { _base: height },
             mWidthType: w_type as u8,
             mHeightType: h_type as u8,
         }
     </%self:simple_image_array_property>
 
-    pub fn clone_${shorthand}_size(&self) -> longhands::background_size::computed_value::T {
+    pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T {
         use gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue;
         use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType;
-        use values::computed::LengthOrPercentageOrAuto;
+        use values::generics::NonNegative;
+        use values::computed::NonNegativeLengthOrPercentageOrAuto;
         use values::generics::background::BackgroundSize;
 
-        fn to_servo(value: CalcValue, ty: u8) -> LengthOrPercentageOrAuto {
+        fn to_servo(value: CalcValue, ty: u8) -> NonNegativeLengthOrPercentageOrAuto {
             if ty == DimensionType::eAuto as u8 {
-                LengthOrPercentageOrAuto::Auto
+                NonNegativeLengthOrPercentageOrAuto::auto()
             } else {
                 debug_assert_eq!(ty, DimensionType::eLengthPercentage as u8);
-                value.into()
+                NonNegative(value.into())
             }
         }
 
-        longhands::background_size::computed_value::T(
+        longhands::${shorthand}_size::computed_value::List(
             self.gecko.${image_layers_field}.mLayers.iter().map(|ref layer| {
                 if DimensionType::eCover as u8 == layer.mSize.mWidthType {
                     debug_assert_eq!(layer.mSize.mHeightType, DimensionType::eCover as u8);
                     return BackgroundSize::Cover
                 }
                 if DimensionType::eContain as u8 == layer.mSize.mWidthType {
                     debug_assert_eq!(layer.mSize.mHeightType, DimensionType::eContain as u8);
                     return BackgroundSize::Contain
@@ -4047,17 +4055,17 @@ fn static_assert() {
                 geckoimage.mImage.set(image)
             }
         }
     }
 
     pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T {
         use values::None_;
 
-        longhands::${shorthand}_image::computed_value::T(
+        longhands::${shorthand}_image::computed_value::List(
             self.gecko.${image_layers_field}.mLayers.iter()
                 .take(self.gecko.${image_layers_field}.mImageCount as usize)
                 .map(|ref layer| {
                     match unsafe { layer.mImage.into_image() } {
                         Some(image) => Either::Second(image),
                         None => Either::First(None_),
                     }
             }).collect()
@@ -4303,17 +4311,17 @@ fn static_assert() {
     }
 
     pub fn reset_box_shadow(&mut self, other: &Self) {
         self.copy_box_shadow_from(other)
     }
 
     pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T {
         let buf = self.gecko.mBoxShadow.iter().map(|v| v.to_box_shadow()).collect();
-        longhands::box_shadow::computed_value::T(buf)
+        longhands::box_shadow::computed_value::List(buf)
     }
 
     pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) {
         use gecko_bindings::structs::NS_STYLE_CLIP_AUTO;
         use gecko_bindings::structs::NS_STYLE_CLIP_RECT;
         use gecko_bindings::structs::NS_STYLE_CLIP_LEFT_AUTO;
         use gecko_bindings::structs::NS_STYLE_CLIP_TOP_AUTO;
         use gecko_bindings::structs::NS_STYLE_CLIP_RIGHT_AUTO;
@@ -4548,17 +4556,17 @@ fn static_assert() {
                     filters.push(Filter::Url(unsafe {
                         let url = RefPtr::new(*filter.__bindgen_anon_1.mURL.as_ref());
                         ComputedUrl::from_url_value(url)
                     }));
                 }
                 _ => {},
             }
         }
-        longhands::filter::computed_value::T(filters)
+        longhands::filter::computed_value::List(filters)
     }
 
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="InheritedBox"
                   skip_longhands="image-orientation">
     // FIXME: Gecko uses a tricky way to store computed value of image-orientation
     //        within an u8. We could inline following glue codes by implementing all
@@ -4669,17 +4677,17 @@ fn static_assert() {
     }
 
     pub fn reset_text_shadow(&mut self, other: &Self) {
         self.copy_text_shadow_from(other)
     }
 
     pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T {
         let buf = self.gecko.mTextShadow.iter().map(|v| v.to_simple_shadow()).collect();
-        longhands::text_shadow::computed_value::T(buf)
+        longhands::text_shadow::computed_value::List(buf)
     }
 
     pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) {
         use values::generics::text::LineHeight;
         // FIXME: Align binary representations and ditch |match| for cast + static_asserts
         let en = match v {
             LineHeight::Normal => CoordDataValue::Normal,
             LineHeight::Length(val) => CoordDataValue::Coord(val.0.to_i32_au()),
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -3,17 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 <%!
     from data import Keyword, to_rust_ident, to_camel_case
     from data import LOGICAL_SIDES, PHYSICAL_SIDES, LOGICAL_SIZES, SYSTEM_FONT_LONGHANDS
 %>
 
 <%def name="predefined_type(name, type, initial_value, parse_method='parse',
-            needs_context=True, vector=False, computed_type=None, initial_specified_value=None,
+            needs_context=True, vector=False,
+            computed_type=None, initial_specified_value=None,
             allow_quirks=False, allow_empty=False, **kwargs)">
     <%def name="predefined_type_inner(name, type, initial_value, parse_method)">
         #[allow(unused_imports)]
         use app_units::Au;
         #[allow(unused_imports)]
         use cssparser::{Color as CSSParserColor, RGBA};
         #[allow(unused_imports)]
         use values::specified::AllowQuirks;
@@ -72,20 +73,22 @@
 <%doc>
     To be used in cases where we have a grammar like "<thing> [ , <thing> ]*".
 
     Setting allow_empty to False allows for cases where the vector
     is empty. The grammar for these is usually "none | <thing> [ , <thing> ]*".
     We assume that the default/initial value is an empty vector for these.
     `initial_value` need not be defined for these.
 </%doc>
-<%def name="vector_longhand(name, animation_value_type=None, allow_empty=False, separator='Comma',
-                            need_animatable=False, **kwargs)">
+<%def name="vector_longhand(name, animation_value_type=None,
+                            vector_animation_type=None, allow_empty=False,
+                            separator='Comma',
+                            **kwargs)">
     <%call expr="longhand(name, animation_value_type=animation_value_type, vector=True,
-                          need_animatable=need_animatable, **kwargs)">
+                          **kwargs)">
         #[allow(unused_imports)]
         use smallvec::SmallVec;
 
         pub mod single_value {
             #[allow(unused_imports)]
             use cssparser::{Parser, BasicParseError};
             #[allow(unused_imports)]
             use parser::{Parse, ParserContext};
@@ -110,46 +113,78 @@
             pub use self::single_value::T as SingleComputedValue;
             % if allow_empty and allow_empty != "NotInitial":
             use std::vec::IntoIter;
             % else:
             use smallvec::{IntoIter, SmallVec};
             % endif
             use values::computed::ComputedVecIter;
 
-            /// The computed value, effectively a list of single values.
+            /// The generic type defining the value for this property.
             % if separator == "Comma":
             #[css(comma)]
             % endif
-            #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
-            % if need_animatable or animation_value_type == "ComputedValue":
-            #[derive(Animate, ComputeSquaredDistance)]
-            % endif
-            pub struct T(
+            #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue,
+                     ToCss)]
+            pub struct List<T>(
                 % if not allow_empty:
                 #[css(iterable)]
                 % else:
                 #[css(if_empty = "none", iterable)]
                 % endif
                 % if allow_empty and allow_empty != "NotInitial":
-                pub Vec<single_value::T>,
+                pub Vec<T>,
                 % else:
-                pub SmallVec<[single_value::T; 1]>,
+                pub SmallVec<[T; 1]>,
                 % endif
             );
 
-            % if need_animatable or animation_value_type == "ComputedValue":
-                use values::animated::{ToAnimatedZero};
+
+            /// The computed value, effectively a list of single values.
+            % if vector_animation_type:
+            % if not animation_value_type:
+                Sorry, this is stupid but needed for now.
+            % endif
+
+            use properties::animated_properties::ListAnimation;
+            use values::animated::{Animate, ToAnimatedValue, ToAnimatedZero, Procedure};
+            use values::distance::{SquaredDistance, ComputeSquaredDistance};
+
+            // FIXME(emilio): For some reason rust thinks that this alias is
+            // unused, even though it's clearly used below?
+            #[allow(unused)]
+            type AnimatedList = <List<single_value::T> as ToAnimatedValue>::AnimatedValue;
+
+            impl ToAnimatedZero for AnimatedList {
+                fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+            }
 
-                impl ToAnimatedZero for T {
-                    #[inline]
-                    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+            impl Animate for AnimatedList {
+                fn animate(
+                    &self,
+                    other: &Self,
+                    procedure: Procedure,
+                ) -> Result<Self, ()> {
+                    Ok(List(
+                        self.0.animate_${vector_animation_type}(&other.0, procedure)?
+                    ))
                 }
+            }
+            impl ComputeSquaredDistance for AnimatedList {
+                fn compute_squared_distance(
+                    &self,
+                    other: &Self,
+                ) -> Result<SquaredDistance, ()> {
+                    self.0.squared_distance_${vector_animation_type}(&other.0)
+                }
+            }
             % endif
 
+            pub type T = List<single_value::T>;
+
             pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;
 
             impl IntoIterator for T {
                 type Item = single_value::T;
                 % if allow_empty and allow_empty != "NotInitial":
                 type IntoIter = IntoIter<single_value::T>;
                 % else:
                 type IntoIter = IntoIter<[single_value::T; 1]>;
@@ -171,54 +206,58 @@
             % else:
             #[css(if_empty = "none", iterable)]
             % endif
             pub Vec<single_value::SpecifiedValue>,
         );
 
         pub fn get_initial_value() -> computed_value::T {
             % if allow_empty and allow_empty != "NotInitial":
-                computed_value::T(vec![])
+                computed_value::List(vec![])
             % else:
                 let mut v = SmallVec::new();
                 v.push(single_value::get_initial_value());
-                computed_value::T(v)
+                computed_value::List(v)
             % endif
         }
 
-        pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-                                -> Result<SpecifiedValue, ParseError<'i>> {
+        pub fn parse<'i, 't>(
+            context: &ParserContext,
+            input: &mut Parser<'i, 't>,
+        ) -> Result<SpecifiedValue, ParseError<'i>> {
             use style_traits::Separator;
 
             % if allow_empty:
                 if input.try(|input| input.expect_ident_matching("none")).is_ok() {
                     return Ok(SpecifiedValue(Vec::new()))
                 }
             % endif
 
             ::style_traits::${separator}::parse(input, |parser| {
                 single_value::parse(context, parser)
             }).map(SpecifiedValue)
         }
 
         pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;
 
         impl SpecifiedValue {
-            pub fn compute_iter<'a, 'cx, 'cx_a>(&'a self, context: &'cx Context<'cx_a>)
-                -> computed_value::Iter<'a, 'cx, 'cx_a> {
+            pub fn compute_iter<'a, 'cx, 'cx_a>(
+                &'a self,
+                context: &'cx Context<'cx_a>,
+            ) -> computed_value::Iter<'a, 'cx, 'cx_a> {
                 computed_value::Iter::new(context, &self.0)
             }
         }
 
         impl ToComputedValue for SpecifiedValue {
             type ComputedValue = computed_value::T;
 
             #[inline]
             fn to_computed_value(&self, context: &Context) -> computed_value::T {
-                computed_value::T(self.compute_iter(context).collect())
+                computed_value::List(self.compute_iter(context).collect())
             }
 
             #[inline]
             fn from_computed_value(computed: &computed_value::T) -> Self {
                 SpecifiedValue(computed.0.iter()
                                     .map(ToComputedValue::from_computed_value)
                                     .collect())
             }
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -24,21 +24,20 @@ use properties::PropertyId;
 use properties::{LonghandId, ShorthandId};
 use servo_arc::Arc;
 use smallvec::SmallVec;
 use std::{cmp, ptr};
 use std::mem::{self, ManuallyDrop};
 #[cfg(feature = "gecko")] use hash::FnvHashMap;
 use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo};
 use super::ComputedValues;
-use values::{CSSFloat, CustomIdent, Either};
+use values::{CSSFloat, CustomIdent};
 use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
 use values::animated::color::RGBA as AnimatedRGBA;
 use values::animated::effects::Filter as AnimatedFilter;
-use values::animated::effects::FilterList as AnimatedFilterList;
 use values::computed::{Angle, CalcLengthOrPercentage};
 use values::computed::{ClipRect, Context};
 use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
 use values::computed::{LengthOrPercentageOrNone, MaxLength};
 use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage};
 use values::computed::length::NonNegativeLengthOrPercentage;
 use values::computed::ToComputedValue;
 use values::computed::transform::{DirectionVector, Matrix, Matrix3D};
@@ -48,23 +47,20 @@ use values::computed::transform::Rotate 
 use values::computed::transform::Translate as ComputedTranslate;
 use values::computed::transform::Scale as ComputedScale;
 use values::computed::url::ComputedUrl;
 use values::generics::transform::{self, Rotate, Translate, Scale, Transform, TransformOperation};
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
 use values::generics::font::{FontSettings as GenericFontSettings, FontTag, VariationValue};
 use values::computed::font::FontVariationSettings;
 use values::generics::effects::Filter;
-use values::generics::position as generic_position;
 use values::generics::svg::{SVGLength,  SvgLengthOrPercentageOrNumber, SVGPaint};
 use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity};
 use void::{self, Void};
 
-/// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
-pub trait RepeatableListAnimatable: Animate {}
 
 /// Returns true if this nsCSSPropertyID is one of the animatable properties.
 #[cfg(feature = "gecko")]
 pub fn nscsspropertyid_is_animatable(property: nsCSSPropertyID) -> bool {
     match property {
         % for prop in data.longhands + data.shorthands_except_all():
             % if prop.animatable:
                 ${prop.nscsspropertyid()} => true,
@@ -750,60 +746,135 @@ impl ToAnimatedZero for AnimationValue {
             },
             % endif
             % endfor
             _ => Err(()),
         }
     }
 }
 
-impl RepeatableListAnimatable for LengthOrPercentage {}
-impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {}
-impl RepeatableListAnimatable for Either<NonNegativeNumber, NonNegativeLengthOrPercentage> {}
-impl RepeatableListAnimatable for SvgLengthOrPercentageOrNumber<LengthOrPercentage, Number> {}
+/// A trait to abstract away the different kind of animations over a list that
+/// there may be.
+pub trait ListAnimation<T> : Sized {
+    /// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
+    fn animate_repeatable_list(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>
+    where
+        T: Animate;
+
+    /// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
+    fn squared_distance_repeatable_list(&self, other: &Self) -> Result<SquaredDistance, ()>
+    where
+        T: ComputeSquaredDistance;
+
+    /// This is the animation used for some of the types like shadows and
+    /// filters, where the interpolation happens with the zero value if one of
+    /// the sides is not present.
+    fn animate_with_zero(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>
+    where
+        T: Animate + Clone + ToAnimatedZero;
 
-macro_rules! repeated_vec_impl {
-    ($($ty:ty),*) => {
-        $(impl<T> Animate for $ty
-        where
-            T: RepeatableListAnimatable,
-        {
-            fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+    /// This is the animation used for some of the types like shadows and
+    /// filters, where the interpolation happens with the zero value if one of
+    /// the sides is not present.
+    fn squared_distance_with_zero(&self, other: &Self) -> Result<SquaredDistance, ()>
+    where
+        T: ToAnimatedZero + ComputeSquaredDistance;
+}
+
+macro_rules! animated_list_impl {
+    (<$t:ident> for $ty:ty) => {
+        impl<$t> ListAnimation<$t> for $ty {
+            fn animate_repeatable_list(
+                &self,
+                other: &Self,
+                procedure: Procedure,
+            ) -> Result<Self, ()>
+            where
+                T: Animate,
+            {
                 // If the length of either list is zero, the least common multiple is undefined.
                 if self.is_empty() || other.is_empty() {
                     return Err(());
                 }
                 use num_integer::lcm;
                 let len = lcm(self.len(), other.len());
                 self.iter().cycle().zip(other.iter().cycle()).take(len).map(|(this, other)| {
                     this.animate(other, procedure)
                 }).collect()
             }
-        }
 
-        impl<T> ComputeSquaredDistance for $ty
-        where
-            T: ComputeSquaredDistance + RepeatableListAnimatable,
-        {
-            #[inline]
-            fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+            fn squared_distance_repeatable_list(
+                &self,
+                other: &Self,
+            ) -> Result<SquaredDistance, ()>
+            where
+                T: ComputeSquaredDistance,
+            {
                 if self.is_empty() || other.is_empty() {
                     return Err(());
                 }
                 use num_integer::lcm;
                 let len = lcm(self.len(), other.len());
                 self.iter().cycle().zip(other.iter().cycle()).take(len).map(|(this, other)| {
                     this.compute_squared_distance(other)
                 }).sum()
             }
-        })*
-    };
+
+            fn animate_with_zero(
+                &self,
+                other: &Self,
+                procedure: Procedure,
+            ) -> Result<Self, ()>
+            where
+                T: Animate + Clone + ToAnimatedZero
+            {
+                if procedure == Procedure::Add {
+                    return Ok(
+                        self.iter().chain(other.iter()).cloned().collect()
+                    );
+                }
+                self.iter().zip_longest(other.iter()).map(|it| {
+                    match it {
+                        EitherOrBoth::Both(this, other) => {
+                            this.animate(other, procedure)
+                        },
+                        EitherOrBoth::Left(this) => {
+                            this.animate(&this.to_animated_zero()?, procedure)
+                        },
+                        EitherOrBoth::Right(other) => {
+                            other.to_animated_zero()?.animate(other, procedure)
+                        }
+                    }
+                }).collect()
+            }
+
+            fn squared_distance_with_zero(
+                &self,
+                other: &Self,
+            ) -> Result<SquaredDistance, ()>
+            where
+                T: ToAnimatedZero + ComputeSquaredDistance
+            {
+                self.iter().zip_longest(other.iter()).map(|it| {
+                    match it {
+                        EitherOrBoth::Both(this, other) => {
+                            this.compute_squared_distance(other)
+                        },
+                        EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
+                            list.to_animated_zero()?.compute_squared_distance(list)
+                        },
+                    }
+                }).sum()
+            }
+        }
+    }
 }
 
-repeated_vec_impl!(SmallVec<[T; 1]>, Vec<T>);
+animated_list_impl!(<T> for SmallVec<[T; 1]>);
+animated_list_impl!(<T> for Vec<T>);
 
 /// <https://drafts.csswg.org/css-transitions/#animtype-visibility>
 impl Animate for Visibility {
     #[inline]
     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
         let (this_weight, other_weight) = procedure.weights();
         match (*self, *other) {
             (Visibility::Visible, _) => {
@@ -1022,19 +1093,16 @@ impl<'a> Iterator for FontSettingTagIter
         ) {
             (Some(at), Some(bt)) if at.tag == bt.tag => Some(Ok((at, bt))),
             (None, None) => None,
             _ => Some(Err(())), // Mismatch number of unique tags or tag names.
         }
     }
 }
 
-impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V>
-    where H: RepeatableListAnimatable, V: RepeatableListAnimatable {}
-
 /// <https://drafts.csswg.org/css-transitions/#animtype-rect>
 impl Animate for ClipRect {
     #[inline]
     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
         use values::computed::Length;
         let animate_component = |this: &Option<Length>, other: &Option<Length>| {
             match (this.animate(other, procedure)?, procedure) {
                 (None, Procedure::Interpolate { .. }) => Ok(None),
@@ -2663,37 +2731,26 @@ impl ComputeSquaredDistance for Computed
             _ => Err(()),
         }
     }
 }
 
 impl ComputeSquaredDistance for ComputedTransform {
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
-        let list1 = &self.0;
-        let list2 = &other.0;
+        let squared_dist = self.0.squared_distance_with_zero(&other.0);
 
-        let squared_dist: Result<SquaredDistance, _> = list1.iter().zip_longest(list2).map(|it| {
-            match it {
-                EitherOrBoth::Both(this, other) => {
-                    this.compute_squared_distance(other)
-                },
-                EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
-                    list.to_animated_zero()?.compute_squared_distance(list)
-                },
-            }
-        }).sum();
-
-        // Roll back to matrix interpolation if there is any Err(()) in the transform lists, such
-        // as mismatched transform functions.
-        if let Err(_) = squared_dist {
+        // Roll back to matrix interpolation if there is any Err(()) in the
+        // transform lists, such as mismatched transform functions.
+        if squared_dist.is_err() {
             let matrix1: Matrix3D = self.to_transform_3d_matrix(None)?.0.into();
             let matrix2: Matrix3D = other.to_transform_3d_matrix(None)?.0.into();
             return matrix1.compute_squared_distance(&matrix2);
         }
+
         squared_dist
     }
 }
 
 /// Animated SVGPaint
 pub type IntermediateSVGPaint = SVGPaint<AnimatedRGBA, ComputedUrl>;
 
 /// Animated SVGPaintKind
@@ -2823,27 +2880,42 @@ where
             _ => Err(()),
         }
     }
 }
 
 /// <https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty>
 impl<L> Animate for SVGStrokeDashArray<L>
 where
-    L: Clone + RepeatableListAnimatable,
+    L: Clone + Animate,
 {
     #[inline]
     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
         if matches!(procedure, Procedure::Add | Procedure::Accumulate { .. }) {
             // Non-additive.
             return Err(());
         }
         match (self, other) {
             (&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => {
-                Ok(SVGStrokeDashArray::Values(this.animate(other, procedure)?))
+                Ok(SVGStrokeDashArray::Values(this.animate_repeatable_list(other, procedure)?))
+            },
+            _ => Err(()),
+        }
+    }
+}
+
+impl<L> ComputeSquaredDistance for SVGStrokeDashArray<L>
+where
+    L: ComputeSquaredDistance,
+{
+    #[inline]
+    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+        match (self, other) {
+            (&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => {
+                this.squared_distance_repeatable_list(other)
             },
             _ => Err(()),
         }
     }
 }
 
 impl<L> ToAnimatedZero for SVGStrokeDashArray<L>
 where
@@ -2924,60 +2996,16 @@ impl ToAnimatedZero for AnimatedFilter {
             % if product == "gecko":
             Filter::DropShadow(ref this) => Ok(Filter::DropShadow(this.to_animated_zero()?)),
             % endif
             _ => Err(()),
         }
     }
 }
 
-impl Animate for AnimatedFilterList {
-    #[inline]
-    fn animate(
-        &self,
-        other: &Self,
-        procedure: Procedure,
-    ) -> Result<Self, ()> {
-        if procedure == Procedure::Add {
-            return Ok(AnimatedFilterList(
-                self.0.iter().chain(other.0.iter()).cloned().collect(),
-            ));
-        }
-        Ok(AnimatedFilterList(self.0.iter().zip_longest(other.0.iter()).map(|it| {
-            match it {
-                EitherOrBoth::Both(this, other) => {
-                    this.animate(other, procedure)
-                },
-                EitherOrBoth::Left(this) => {
-                    this.animate(&this.to_animated_zero()?, procedure)
-                },
-                EitherOrBoth::Right(other) => {
-                    other.to_animated_zero()?.animate(other, procedure)
-                },
-            }
-        }).collect::<Result<Vec<_>, _>>()?))
-    }
-}
-
-impl ComputeSquaredDistance for AnimatedFilterList {
-    #[inline]
-    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
-        self.0.iter().zip_longest(other.0.iter()).map(|it| {
-            match it {
-                EitherOrBoth::Both(this, other) => {
-                    this.compute_squared_distance(other)
-                },
-                EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
-                    list.to_animated_zero()?.compute_squared_distance(list)
-                },
-            }
-        }).sum()
-    }
-}
-
 /// A comparator to sort PropertyIds such that longhands are sorted before shorthands,
 /// shorthands with fewer components are sorted before shorthands with more components,
 /// and otherwise shorthands are sorted by IDL name as defined by [Web Animations][property-order].
 ///
 /// Using this allows us to prioritize values specified by longhands (or smaller
 /// shorthand subsets) when longhands and shorthands are both specified on the one keyframe.
 ///
 /// Example orderings that result from this:
--- a/servo/components/style/properties/longhand/background.mako.rs
+++ b/servo/components/style/properties/longhand/background.mako.rs
@@ -31,16 +31,17 @@
     ${helpers.predefined_type(
         "background-position-" + axis,
         "position::" + direction + "Position",
         initial_value="computed::LengthOrPercentage::zero()",
         initial_specified_value="SpecifiedValue::initial_specified_value()",
         spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis,
         animation_value_type="ComputedValue",
         vector=True,
+        vector_animation_type="repeatable_list",
         flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
     )}
 % endfor
 
 ${helpers.predefined_type(
     "background-repeat",
     "BackgroundRepeat",
     "computed::BackgroundRepeat::repeat()",
@@ -71,23 +72,25 @@
 ${helpers.single_keyword("background-origin",
                          "padding-box border-box content-box",
                          vector=True, extra_prefixes="webkit",
                          gecko_enum_prefix="StyleGeometryBox",
                          spec="https://drafts.csswg.org/css-backgrounds/#the-background-origin",
                          animation_value_type="discrete",
                          flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")}
 
-${helpers.predefined_type("background-size", "BackgroundSize",
+${helpers.predefined_type(
+    "background-size",
+    "BackgroundSize",
     initial_value="computed::BackgroundSize::auto()",
     initial_specified_value="specified::BackgroundSize::auto()",
     spec="https://drafts.csswg.org/css-backgrounds/#the-background-size",
     vector=True,
+    vector_animation_type="repeatable_list",
     animation_value_type="BackgroundSizeList",
-    need_animatable=True,
     flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
     extra_prefixes="webkit")}
 
 // https://drafts.fxtf.org/compositing/#background-blend-mode
 ${helpers.single_keyword("background-blend-mode",
                          """normal multiply screen overlay darken lighten color-dodge
                             color-burn hard-light soft-light difference exclusion hue
                             saturation color luminosity""",
--- a/servo/components/style/properties/longhand/effects.mako.rs
+++ b/servo/components/style/properties/longhand/effects.mako.rs
@@ -19,16 +19,17 @@
 )}
 
 ${helpers.predefined_type(
     "box-shadow",
     "BoxShadow",
     None,
     vector=True,
     animation_value_type="AnimatedBoxShadowList",
+    vector_animation_type="with_zero",
     extra_prefixes="webkit",
     ignored_when_colors_disabled=True,
     flags="APPLIES_TO_FIRST_LETTER",
     spec="https://drafts.csswg.org/css-backgrounds/#box-shadow",
 )}
 
 ${helpers.predefined_type("clip",
                           "ClipRectOrAuto",
@@ -40,16 +41,17 @@
 
 ${helpers.predefined_type(
     "filter",
     "Filter",
     None,
     vector=True,
     separator="Space",
     animation_value_type="AnimatedFilterList",
+    vector_animation_type="with_zero",
     extra_prefixes="webkit",
     flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
     spec="https://drafts.fxtf.org/filters/#propdef-filter",
 )}
 
 ${helpers.single_keyword("mix-blend-mode",
                          """normal multiply screen overlay darken lighten color-dodge
                             color-burn hard-light soft-light difference exclusion hue
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -79,17 +79,17 @@
                           initial_value="specified::FontSynthesis::get_initial_value()",
                           animation_value_type="discrete",
                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-synthesis")}
 
 ${helpers.predefined_type(
     "font-stretch",
     "FontStretch",
-    initial_value="computed::NonNegativePercentage::hundred()",
+    initial_value="computed::FontStretch::hundred()",
     initial_specified_value="specified::FontStretch::normal()",
     animation_value_type="Percentage",
     flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
     spec="https://drafts.csswg.org/css-fonts/#propdef-font-stretch",
     servo_restyle_damage="rebuild_and_reflow",
 )}
 
 ${helpers.single_keyword_system("font-kerning",
@@ -330,17 +330,17 @@ https://drafts.csswg.org/css-fonts-4/#lo
         impl ToComputedValue for SystemFont {
             type ComputedValue = ComputedSystemFont;
 
             fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
                 use gecko_bindings::bindings;
                 use gecko_bindings::structs::{LookAndFeel_FontID, nsFont};
                 use std::mem;
                 use values::computed::Percentage;
-                use values::computed::font::{FontSize, FontStyle, FontFamilyList};
+                use values::computed::font::{FontSize, FontStretch, FontStyle, FontFamilyList};
                 use values::generics::NonNegative;
 
                 let id = match *self {
                     % for font in system_fonts:
                         SystemFont::${to_camel_case(font)} => {
                             LookAndFeel_FontID::eFont_${to_camel_case(font.replace("-moz-", ""))}
                         }
                     % endfor
@@ -351,19 +351,19 @@ https://drafts.csswg.org/css-fonts-4/#lo
                     bindings::Gecko_nsFont_InitSystem(
                         &mut system,
                         id as i32,
                         cx.style().get_font().gecko(),
                         cx.device().pres_context()
                     )
                 }
                 let font_weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight);
-                let font_stretch = NonNegative(Percentage(unsafe {
+                let font_stretch = FontStretch(NonNegative(Percentage(unsafe {
                     bindings::Gecko_FontStretch_ToFloat(system.stretch)
-                }));
+                })));
                 let font_style = FontStyle::from_gecko(system.style);
                 let ret = ComputedSystemFont {
                     font_family: longhands::font_family::computed_value::T(
                         FontFamilyList(
                             unsafe { system.fontlist.mFontlist.mBasePtr.to_safe() }
                         )
                     ),
                     font_size: FontSize {
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -187,16 +187,17 @@
     % endif
 </%helpers:single_keyword>
 
 ${helpers.predefined_type(
     "text-shadow",
     "SimpleShadow",
     None,
     vector=True,
+    vector_animation_type="with_zero",
     animation_value_type="AnimatedTextShadowList",
     ignored_when_colors_disabled=True,
     flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
     spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property",
 )}
 
 ${helpers.predefined_type(
     "text-emphasis-style",
--- a/servo/components/style/properties/longhand/svg.mako.rs
+++ b/servo/components/style/properties/longhand/svg.mako.rs
@@ -98,16 +98,17 @@
         "mask-position-" + axis,
         "position::" + direction + "Position",
         products="gecko",
         extra_prefixes="webkit",
         initial_value="computed::LengthOrPercentage::zero()",
         initial_specified_value="specified::PositionComponent::Center",
         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position",
         animation_value_type="ComputedValue",
+        vector_animation_type="repeatable_list",
         vector=True,
     )}
 % endfor
 
 ${helpers.single_keyword("mask-clip",
                          "border-box content-box padding-box",
                          extra_gecko_values="fill-box stroke-box view-box no-clip",
                          vector=True,
@@ -121,36 +122,28 @@
                          "border-box content-box padding-box",
                          extra_gecko_values="fill-box stroke-box view-box",
                          vector=True,
                          products="gecko",
                          extra_prefixes="webkit",
                          gecko_enum_prefix="StyleGeometryBox",
                          animation_value_type="discrete",
                          spec="https://drafts.fxtf.org/css-masking/#propdef-mask-origin")}
-
-<%helpers:longhand name="mask-size" products="gecko" animation_value_type="ComputedValue" extra_prefixes="webkit"
-                   spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size">
-    use properties::longhands::background_size;
-    pub use ::properties::longhands::background_size::SpecifiedValue;
-    pub use ::properties::longhands::background_size::single_value as single_value;
-    pub use ::properties::longhands::background_size::computed_value as computed_value;
-
-    #[inline]
-    pub fn get_initial_value() -> computed_value::T {
-        background_size::get_initial_value()
-    }
-
-    pub fn parse<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<SpecifiedValue, ParseError<'i>> {
-        background_size::parse(context, input)
-    }
-</%helpers:longhand>
+${helpers.predefined_type(
+    "mask-size",
+    "background::BackgroundSize",
+    "computed::BackgroundSize::auto()",
+    initial_specified_value="specified::BackgroundSize::auto()",
+    products="gecko",
+    extra_prefixes="webkit",
+    spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size",
+    animation_value_type="MaskSizeList",
+    vector=True,
+    vector_animation_type="repeatable_list",
+)}
 
 ${helpers.single_keyword("mask-composite",
                          "add subtract intersect exclude",
                          vector=True,
                          products="gecko",
                          extra_prefixes="webkit",
                          animation_value_type="discrete",
                          spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -2211,22 +2211,23 @@ pub mod style_structs {
                 % if longhand.logical:
                     ${helpers.logical_setter(name=longhand.name)}
                 % else:
                     % if longhand.is_vector:
                         /// Set ${longhand.name}.
                         #[allow(non_snake_case)]
                         #[inline]
                         pub fn set_${longhand.ident}<I>(&mut self, v: I)
-                            where I: IntoIterator<Item = longhands::${longhand.ident}
-                                                                  ::computed_value::single_value::T>,
-                                  I::IntoIter: ExactSizeIterator
+                        where
+                            I: IntoIterator<Item = longhands::${longhand.ident}
+                                                              ::computed_value::single_value::T>,
+                            I::IntoIter: ExactSizeIterator
                         {
                             self.${longhand.ident} = longhands::${longhand.ident}::computed_value
-                                                              ::T(v.into_iter().collect());
+                                                              ::List(v.into_iter().collect());
                         }
                     % elif longhand.ident == "display":
                         /// Set `display`.
                         ///
                         /// We need to keep track of the original display for hypothetical boxes,
                         /// so we need to special-case this.
                         #[allow(non_snake_case)]
                         #[inline]
@@ -2300,23 +2301,20 @@ pub mod style_structs {
                     }
                 % endfor
             % elif style_struct.name == "Font":
                 /// Computes a font hash in order to be able to cache fonts
                 /// effectively in GFX and layout.
                 pub fn compute_font_hash(&mut self) {
                     // Corresponds to the fields in
                     // `gfx::font_template::FontTemplateDescriptor`.
-                    //
-                    // FIXME(emilio): Where's font-style?
                     let mut hasher: FnvHasher = Default::default();
-                    // We hash the floating point number with four decimal
-                    // places.
-                    hasher.write_u64((self.font_weight.0 * 10000.).trunc() as u64);
-                    hasher.write_u64(((self.font_stretch.0).0 * 10000.).trunc() as u64);
+                    self.font_weight.hash(&mut hasher);
+                    self.font_stretch.hash(&mut hasher);
+                    self.font_style.hash(&mut hasher);
                     self.font_family.hash(&mut hasher);
                     self.hash = hasher.finish()
                 }
 
                 /// (Servo does not handle MathML, so this just calls copy_font_size_from)
                 pub fn inherit_font_size_from(&mut self, parent: &Self,
                                               _: Option<NonNegativeLength>,
                                               _: &Device) {
@@ -2402,17 +2400,17 @@ pub mod style_structs {
 
                 /// Clone the computed value for the property.
                 #[allow(non_snake_case)]
                 #[inline]
                 #[cfg(feature = "gecko")]
                 pub fn clone_${longhand.ident}(
                     &self,
                 ) -> longhands::${longhand.ident}::computed_value::T {
-                    longhands::${longhand.ident}::computed_value::T(
+                    longhands::${longhand.ident}::computed_value::List(
                         self.${longhand.ident}_iter().collect()
                     )
                 }
             % endif
         % endfor
 
         % if style_struct.name == "Box":
             /// Returns whether there is any animation specified with
--- a/servo/components/style/properties/shorthand/mask.mako.rs
+++ b/servo/components/style/properties/shorthand/mask.mako.rs
@@ -183,34 +183,37 @@
 
 <%helpers:shorthand name="mask-position" products="gecko" extra_prefixes="webkit"
                     sub_properties="mask-position-x mask-position-y"
                     spec="https://drafts.csswg.org/css-masks-4/#the-mask-position">
     use properties::longhands::{mask_position_x,mask_position_y};
     use values::specified::position::Position;
     use parser::Parse;
 
-    pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-                               -> Result<Longhands, ParseError<'i>> {
+    pub fn parse_value<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Longhands, ParseError<'i>> {
         // Vec grows from 0 to 4 by default on first push().  So allocate with
         // capacity 1, so in the common case of only one item we don't way
         // overallocate.  Note that we always push at least one item if parsing
         // succeeds.
         let mut position_x = mask_position_x::SpecifiedValue(Vec::with_capacity(1));
         let mut position_y = mask_position_y::SpecifiedValue(Vec::with_capacity(1));
         let mut any = false;
 
         input.parse_comma_separated(|input| {
             let value = Position::parse(context, input)?;
             position_x.0.push(value.horizontal);
             position_y.0.push(value.vertical);
             any = true;
             Ok(())
         })?;
-        if any == false {
+
+        if !any {
             return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
         }
 
         Ok(expanded! {
             mask_position_x: position_x,
             mask_position_y: position_y,
         })
     }
--- a/servo/components/style/values/animated/effects.rs
+++ b/servo/components/style/values/animated/effects.rs
@@ -1,166 +1,42 @@
 /* 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/. */
 
 //! Animated types for CSS values related to effects.
 
-use properties::longhands::box_shadow::computed_value::T as ComputedBoxShadowList;
-use properties::longhands::filter::computed_value::T as ComputedFilterList;
-use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowList;
-use std::cmp;
 #[cfg(not(feature = "gecko"))]
 use values::Impossible;
-use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
 use values::animated::color::RGBA;
 use values::computed::{Angle, Number};
 use values::computed::length::Length;
 #[cfg(feature = "gecko")]
 use values::computed::url::ComputedUrl;
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
 use values::generics::effects::BoxShadow as GenericBoxShadow;
 use values::generics::effects::Filter as GenericFilter;
 use values::generics::effects::SimpleShadow as GenericSimpleShadow;
 
-/// An animated value for the `box-shadow` property.
-pub type BoxShadowList = ShadowList<BoxShadow>;
-
-/// An animated value for the `text-shadow` property.
-pub type TextShadowList = ShadowList<SimpleShadow>;
-
-/// An animated value for shadow lists.
-///
-/// <https://drafts.csswg.org/css-transitions/#animtype-shadow-list>
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
-#[derive(Clone, Debug, PartialEq)]
-pub struct ShadowList<Shadow>(Vec<Shadow>);
-
 /// An animated value for a single `box-shadow`.
 pub type BoxShadow = GenericBoxShadow<Option<RGBA>, Length, Length, Length>;
 
-/// An animated value for the `filter` property.
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
-#[derive(Clone, Debug, PartialEq)]
-pub struct FilterList(pub Vec<Filter>);
-
 /// An animated value for a single `filter`.
 #[cfg(feature = "gecko")]
 pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>;
 
 /// An animated value for a single `filter`.
 #[cfg(not(feature = "gecko"))]
 pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
 
 /// An animated value for the `drop-shadow()` filter.
 pub type SimpleShadow = GenericSimpleShadow<Option<RGBA>, Length, Length>;
 
-impl ToAnimatedValue for ComputedBoxShadowList {
-    type AnimatedValue = BoxShadowList;
-
-    #[inline]
-    fn to_animated_value(self) -> Self::AnimatedValue {
-        ShadowList(self.0.to_animated_value())
-    }
-
-    #[inline]
-    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
-        ComputedBoxShadowList(ToAnimatedValue::from_animated_value(animated.0))
-    }
-}
-
-impl<S> Animate for ShadowList<S>
-where
-    S: Animate + Clone + ToAnimatedZero,
-{
-    #[inline]
-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
-        if procedure == Procedure::Add {
-            return Ok(ShadowList(self.0.iter().chain(&other.0).cloned().collect()));
-        }
-        // FIXME(nox): Use itertools here, to avoid the need for `unreachable!`.
-        let max_len = cmp::max(self.0.len(), other.0.len());
-        let mut shadows = Vec::with_capacity(max_len);
-        for i in 0..max_len {
-            shadows.push(match (self.0.get(i), other.0.get(i)) {
-                (Some(shadow), Some(other)) => shadow.animate(other, procedure)?,
-                (Some(shadow), None) => shadow.animate(&shadow.to_animated_zero()?, procedure)?,
-                (None, Some(shadow)) => shadow.to_animated_zero()?.animate(shadow, procedure)?,
-                (None, None) => unreachable!(),
-            });
-        }
-        Ok(ShadowList(shadows))
-    }
-}
-
-impl<S> ComputeSquaredDistance for ShadowList<S>
-where
-    S: ComputeSquaredDistance + ToAnimatedZero,
-{
-    #[inline]
-    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
-        use itertools::{EitherOrBoth, Itertools};
-
-        self.0
-            .iter()
-            .zip_longest(other.0.iter())
-            .map(|it| match it {
-                EitherOrBoth::Both(from, to) => from.compute_squared_distance(to),
-                EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
-                    list.compute_squared_distance(&list.to_animated_zero()?)
-                },
-            })
-            .sum()
-    }
-}
-
-impl<S> ToAnimatedZero for ShadowList<S> {
-    #[inline]
-    fn to_animated_zero(&self) -> Result<Self, ()> {
-        Ok(ShadowList(vec![]))
-    }
-}
-
-impl ToAnimatedValue for ComputedTextShadowList {
-    type AnimatedValue = TextShadowList;
-
-    #[inline]
-    fn to_animated_value(self) -> Self::AnimatedValue {
-        ShadowList(self.0.to_animated_value())
-    }
-
-    #[inline]
-    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
-        ComputedTextShadowList(ToAnimatedValue::from_animated_value(animated.0))
-    }
-}
-
 impl ComputeSquaredDistance for BoxShadow {
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
         if self.inset != other.inset {
             return Err(());
         }
         Ok(self.base.compute_squared_distance(&other.base)? +
             self.spread.compute_squared_distance(&other.spread)?)
     }
 }
-
-impl ToAnimatedValue for ComputedFilterList {
-    type AnimatedValue = FilterList;
-
-    #[inline]
-    fn to_animated_value(self) -> Self::AnimatedValue {
-        FilterList(self.0.to_animated_value())
-    }
-
-    #[inline]
-    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
-        ComputedFilterList(ToAnimatedValue::from_animated_value(animated.0))
-    }
-}
-
-impl ToAnimatedZero for FilterList {
-    #[inline]
-    fn to_animated_zero(&self) -> Result<Self, ()> {
-        Ok(FilterList(vec![]))
-    }
-}
--- a/servo/components/style/values/animated/mod.rs
+++ b/servo/components/style/values/animated/mod.rs
@@ -6,16 +6,17 @@
 //!
 //! Some values, notably colors, cannot be interpolated directly with their
 //! computed values and need yet another intermediate representation. This
 //! module's raison d'ĂȘtre is to ultimately contain all these types.
 
 use app_units::Au;
 use euclid::{Point2D, Size2D};
 use smallvec::SmallVec;
+use values::computed::length::CalcLengthOrPercentage;
 use values::computed::Angle as ComputedAngle;
 use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
 use values::computed::MaxLength as ComputedMaxLength;
 use values::computed::MozLength as ComputedMozLength;
 use values::computed::url::ComputedUrl;
 
 pub mod color;
 pub mod effects;
@@ -252,16 +253,17 @@ macro_rules! trivial_to_animated_value {
             fn from_animated_value(animated: Self::AnimatedValue) -> Self {
                 animated
             }
         }
     };
 }
 
 trivial_to_animated_value!(Au);
+trivial_to_animated_value!(CalcLengthOrPercentage);
 trivial_to_animated_value!(ComputedAngle);
 trivial_to_animated_value!(ComputedUrl);
 trivial_to_animated_value!(bool);
 trivial_to_animated_value!(f32);
 
 impl ToAnimatedValue for ComputedBorderCornerRadius {
     type AnimatedValue = Self;
 
--- a/servo/components/style/values/computed/background.rs
+++ b/servo/components/style/values/computed/background.rs
@@ -1,93 +1,35 @@
 /* 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/. */
 
 //! Computed types for CSS values related to backgrounds.
 
-use properties::animated_properties::RepeatableListAnimatable;
-use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
 use std::fmt::{self, Write};
 use style_traits::{CssWriter, ToCss};
-use values::animated::{ToAnimatedValue, ToAnimatedZero};
 use values::computed::{Context, ToComputedValue};
-use values::computed::length::LengthOrPercentageOrAuto;
+use values::computed::length::NonNegativeLengthOrPercentageOrAuto;
 use values::generics::background::BackgroundSize as GenericBackgroundSize;
 use values::specified::background::BackgroundRepeat as SpecifiedBackgroundRepeat;
 use values::specified::background::BackgroundRepeatKeyword;
 
 /// A computed value for the `background-size` property.
-pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>;
+pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthOrPercentageOrAuto>;
 
 impl BackgroundSize {
     /// Returns `auto auto`.
     pub fn auto() -> Self {
         GenericBackgroundSize::Explicit {
-            width: LengthOrPercentageOrAuto::Auto,
-            height: LengthOrPercentageOrAuto::Auto,
+            width: NonNegativeLengthOrPercentageOrAuto::auto(),
+            height: NonNegativeLengthOrPercentageOrAuto::auto(),
         }
     }
 }
 
-impl RepeatableListAnimatable for BackgroundSize {}
-
-impl ToAnimatedZero for BackgroundSize {
-    #[inline]
-    fn to_animated_zero(&self) -> Result<Self, ()> {
-        Err(())
-    }
-}
-
-impl ToAnimatedValue for BackgroundSize {
-    type AnimatedValue = Self;
-
-    #[inline]
-    fn to_animated_value(self) -> Self {
-        self
-    }
-
-    #[inline]
-    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
-        use values::computed::{Length, Percentage};
-        let clamp_animated_value = |value: LengthOrPercentageOrAuto| -> LengthOrPercentageOrAuto {
-            match value {
-                LengthOrPercentageOrAuto::Length(len) => {
-                    LengthOrPercentageOrAuto::Length(Length::new(len.px().max(0.)))
-                },
-                LengthOrPercentageOrAuto::Percentage(percent) => {
-                    LengthOrPercentageOrAuto::Percentage(Percentage(percent.0.max(0.)))
-                },
-                _ => value,
-            }
-        };
-        match animated {
-            GenericBackgroundSize::Explicit { width, height } => GenericBackgroundSize::Explicit {
-                width: clamp_animated_value(width),
-                height: clamp_animated_value(height),
-            },
-            _ => animated,
-        }
-    }
-}
-
-impl ToAnimatedValue for BackgroundSizeList {
-    type AnimatedValue = Self;
-
-    #[inline]
-    fn to_animated_value(self) -> Self {
-        self
-    }
-
-    #[inline]
-    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
-        BackgroundSizeList(ToAnimatedValue::from_animated_value(animated.0))
-    }
-}
-
 /// The computed value of the `background-repeat` property:
 ///
 /// https://drafts.csswg.org/css-backgrounds/#the-background-repeat
 #[derive(Clone, Debug, MallocSizeOf, PartialEq)]
 pub struct BackgroundRepeat(pub BackgroundRepeatKeyword, pub BackgroundRepeatKeyword);
 
 impl BackgroundRepeat {
     /// Returns the `repeat repeat` value.
--- a/servo/components/style/values/computed/font.rs
+++ b/servo/components/style/values/computed/font.rs
@@ -10,42 +10,47 @@ use byteorder::{BigEndian, ByteOrder};
 use cssparser::{serialize_identifier, CssStringWriter, Parser};
 #[cfg(feature = "gecko")]
 use gecko_bindings::{bindings, structs};
 #[cfg(feature = "gecko")]
 use gecko_bindings::sugar::refptr::RefPtr;
 #[cfg(feature = "gecko")]
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use std::fmt::{self, Write};
-#[cfg(feature = "gecko")]
 use std::hash::{Hash, Hasher};
 #[cfg(feature = "servo")]
 use std::slice;
 use style_traits::{CssWriter, ParseError, ToCss};
 use values::CSSFloat;
 use values::animated::{ToAnimatedValue, ToAnimatedZero};
-use values::computed::{Angle, Context, Integer, NonNegativeLength, Number, ToComputedValue};
+use values::computed::{Angle, Context, Integer, NonNegativeLength, NonNegativePercentage};
+use values::computed::{Number, Percentage, ToComputedValue};
 use values::generics::font::{self as generics, FeatureTagValue, FontSettings, VariationValue};
 use values::specified::font::{self as specified, MIN_FONT_WEIGHT, MAX_FONT_WEIGHT};
 use values::specified::length::{FontBaseSize, NoCalcLength};
 
 pub use values::computed::Length as MozScriptMinSize;
 pub use values::specified::font::{FontSynthesis, MozScriptSizeMultiplier, XLang, XTextZoom};
-pub use values::computed::NonNegativePercentage as FontStretch;
 
 /// A value for the font-weight property per:
 ///
 /// https://drafts.csswg.org/css-fonts-4/#propdef-font-weight
 ///
 /// This is effectively just a `Number`.
 #[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq,
          ToCss)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 pub struct FontWeight(pub Number);
 
+impl Hash for FontWeight {
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        hasher.write_u64((self.0 * 10000.).trunc() as u64);
+    }
+}
+
 impl ToAnimatedValue for FontWeight {
     type AnimatedValue = Number;
 
     #[inline]
     fn to_animated_value(self) -> Self::AnimatedValue {
         self.0
     }
 
@@ -848,16 +853,22 @@ impl ToAnimatedValue for FontStyleAngle 
         FontStyleAngle(Angle::Deg(
             animated.degrees()
                 .min(specified::FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES)
                 .max(specified::FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES)
         ))
     }
 }
 
+impl Hash for FontStyleAngle {
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        hasher.write_u64((self.0.degrees() * 10000.).trunc() as u64);
+    }
+}
+
 /// The computed value of `font-style`.
 ///
 /// FIXME(emilio): Angle should be a custom type to handle clamping during
 /// animation.
 pub type FontStyle = generics::FontStyle<FontStyleAngle>;
 
 impl FontStyle {
     /// The `normal` value.
@@ -911,8 +922,48 @@ impl ToCss for FontStyle {
                     dest.write_char(' ')?;
                     angle.to_css(dest)?;
                 }
                 Ok(())
             }
         }
     }
 }
+
+/// A value for the font-stretch property per:
+///
+/// https://drafts.csswg.org/css-fonts-4/#propdef-font-stretch
+#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss)]
+#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
+pub struct FontStretch(pub NonNegativePercentage);
+
+impl FontStretch {
+    /// 100%
+    pub fn hundred() -> Self {
+        FontStretch(NonNegativePercentage::hundred())
+    }
+
+    /// The float value of the percentage
+    #[inline]
+    pub fn value(&self) -> CSSFloat {
+        ((self.0).0).0
+    }
+}
+
+impl ToAnimatedValue for FontStretch {
+    type AnimatedValue = Percentage;
+
+    #[inline]
+    fn to_animated_value(self) -> Self::AnimatedValue {
+        self.0.to_animated_value()
+    }
+
+    #[inline]
+    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+        FontStretch(NonNegativePercentage::from_animated_value(animated))
+    }
+}
+
+impl Hash for FontStretch {
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        hasher.write_u64((self.value() * 10000.).trunc() as u64);
+    }
+}
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -319,18 +319,18 @@ impl ToComputedValue for specified::Calc
             ..Default::default()
         }
     }
 }
 
 #[allow(missing_docs)]
 #[animate(fallback = "Self::animate_fallback")]
 #[css(derive_debug)]
-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, ToAnimatedZero,
-         ToCss)]
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq,
+         ToAnimatedValue, ToAnimatedZero, ToCss)]
 #[distance(fallback = "Self::compute_squared_distance_fallback")]
 pub enum LengthOrPercentage {
     Length(Length),
     Percentage(Percentage),
     Calc(CalcLengthOrPercentage),
 }
 
 impl LengthOrPercentage {
--- a/servo/components/style/values/computed/percentage.rs
+++ b/servo/components/style/values/computed/percentage.rs
@@ -9,17 +9,17 @@ use style_traits::{CssWriter, ToCss};
 use values::{serialize_percentage, CSSFloat};
 use values::animated::ToAnimatedValue;
 use values::generics::NonNegative;
 
 /// A computed percentage.
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default,
          MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo,
-         ToAnimatedZero, ToComputedValue)]
+         ToAnimatedValue, ToAnimatedZero, ToComputedValue)]
 pub struct Percentage(pub CSSFloat);
 
 impl Percentage {
     /// 0%
     #[inline]
     pub fn zero() -> Self {
         Percentage(0.)
     }
--- a/servo/components/style/values/generics/background.rs
+++ b/servo/components/style/values/generics/background.rs
@@ -1,17 +1,18 @@
 /* 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/. */
 
 //! Generic types for CSS values related to backgrounds.
 
 /// A generic value for the `background-size` property.
 #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
-         PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
+         PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
+         ToComputedValue, ToCss)]
 pub enum BackgroundSize<LengthOrPercentageOrAuto> {
     /// `<width> <height>`
     Explicit {
         /// Explicit width.
         width: LengthOrPercentageOrAuto,
         /// Explicit height.
         height: LengthOrPercentageOrAuto,
     },
--- a/servo/components/style/values/generics/font.rs
+++ b/servo/components/style/values/generics/font.rs
@@ -223,17 +223,17 @@ impl Default for KeywordSize {
     }
 }
 
 /// A generic value for the `font-style` property.
 ///
 /// https://drafts.csswg.org/css-fonts-4/#font-style-prop
 #[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Hash, MallocSizeOf,
          PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero)]
 pub enum FontStyle<Angle> {
     #[animation(error)]
     Normal,
     #[animation(error)]
     Italic,
     #[value_info(starts_with_keyword)]
     Oblique(Angle),
--- a/servo/components/style/values/generics/mod.rs
+++ b/servo/components/style/values/generics/mod.rs
@@ -151,17 +151,17 @@ impl SpecifiedValueInfo for CounterStyle
             }
         }
         include!("../../counter_style/predefined.rs");
     }
 }
 
 /// A wrapper of Non-negative values.
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Hash, MallocSizeOf,
          PartialEq, PartialOrd, SpecifiedValueInfo, ToAnimatedZero,
          ToComputedValue, ToCss)]
 pub struct NonNegative<T>(pub T);
 
 /// A wrapper of greater-than-or-equal-to-one values.
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
          PartialEq, PartialOrd, SpecifiedValueInfo, ToAnimatedZero,
--- a/servo/components/style/values/generics/svg.rs
+++ b/servo/components/style/values/generics/svg.rs
@@ -197,24 +197,23 @@ impl<LengthOrPercentageType: Parse, Numb
 pub enum SVGLength<LengthType> {
     /// `<length> | <percentage> | <number>`
     Length(LengthType),
     /// `context-value`
     ContextValue,
 }
 
 /// Generic value for stroke-dasharray.
-#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
+#[derive(Clone, Debug, MallocSizeOf, PartialEq,
          SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)]
 pub enum SVGStrokeDashArray<LengthType> {
     /// `[ <length> | <percentage> | <number> ]#`
     #[css(comma)]
     Values(
         #[css(if_empty = "none", iterable)]
-        #[distance(field_bound)]
         Vec<LengthType>,
     ),
     /// `context-value`
     ContextValue,
 }
 
 /// An SVG opacity value accepts `context-{fill,stroke}-opacity` in
 /// addition to opacity value.
--- a/servo/components/style/values/specified/background.rs
+++ b/servo/components/style/values/specified/background.rs
@@ -4,50 +4,45 @@
 
 //! Specified types for CSS values related to backgrounds.
 
 use cssparser::Parser;
 use parser::{Parse, ParserContext};
 use selectors::parser::SelectorParseErrorKind;
 use style_traits::ParseError;
 use values::generics::background::BackgroundSize as GenericBackgroundSize;
-use values::specified::length::LengthOrPercentageOrAuto;
+use values::specified::length::NonNegativeLengthOrPercentageOrAuto;
 
 /// A specified value for the `background-size` property.
-pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>;
+pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthOrPercentageOrAuto>;
 
 impl Parse for BackgroundSize {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
-        if let Ok(width) = input.try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) {
+        if let Ok(width) = input.try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i)) {
             let height = input
-                .try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i))
-                .unwrap_or(LengthOrPercentageOrAuto::Auto);
+                .try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i))
+                .unwrap_or(NonNegativeLengthOrPercentageOrAuto::auto());
             return Ok(GenericBackgroundSize::Explicit { width, height });
         }
-        let location = input.current_source_location();
-        let ident = input.expect_ident()?;
-        (match_ignore_ascii_case! { &ident,
-            "cover" => Ok(GenericBackgroundSize::Cover),
-            "contain" => Ok(GenericBackgroundSize::Contain),
-            _ => Err(()),
-        }).map_err(|()| {
-            location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
+        Ok(try_match_ident_ignore_ascii_case! { input,
+            "cover" => GenericBackgroundSize::Cover,
+            "contain" => GenericBackgroundSize::Contain,
         })
     }
 }
 
 impl BackgroundSize {
     /// Returns `auto auto`.
     pub fn auto() -> Self {
         GenericBackgroundSize::Explicit {
-            width: LengthOrPercentageOrAuto::Auto,
-            height: LengthOrPercentageOrAuto::Auto,
+            width: NonNegativeLengthOrPercentageOrAuto::auto(),
+            height: NonNegativeLengthOrPercentageOrAuto::auto(),
         }
     }
 }
 
 /// One of the keywords for `background-repeat`.
 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
          SpecifiedValueInfo, ToComputedValue, ToCss)]
 #[allow(missing_docs)]
--- a/servo/components/style/values/specified/font.rs
+++ b/servo/components/style/values/specified/font.rs
@@ -485,32 +485,32 @@ impl Parse for FontStretch {
             return Ok(FontStretch::Stretch(percentage));
         }
 
         Ok(FontStretch::Keyword(FontStretchKeyword::parse(input)?))
     }
 }
 
 impl ToComputedValue for FontStretch {
-    type ComputedValue = NonNegative<ComputedPercentage>;
+    type ComputedValue = computed::FontStretch;
 
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
         match *self {
             FontStretch::Stretch(ref percentage) => {
-                NonNegative(percentage.to_computed_value(context))
+                computed::FontStretch(NonNegative(percentage.to_computed_value(context)))
             },
             FontStretch::Keyword(ref kw) => {
-                NonNegative(kw.compute())
+                computed::FontStretch(NonNegative(kw.compute()))
             },
             FontStretch::System(_) => self.compute_system(context),
         }
     }
 
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
-        FontStretch::Stretch(Percentage::from_computed_value(&computed.0))
+        FontStretch::Stretch(Percentage::from_computed_value(&(computed.0).0))
     }
 }
 
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
 /// A specified font-size value
 pub enum FontSize {
     /// A length; e.g. 10px.
     Length(LengthOrPercentage),
--- a/testing/web-platform/meta/workers/semantics/structured-clone/dedicated.html.ini
+++ b/testing/web-platform/meta/workers/semantics/structured-clone/dedicated.html.ini
@@ -214,22 +214,16 @@
     expected: TIMEOUT
 
   [Object with non-writable property]
     expected: TIMEOUT
 
   [Object with non-configurable property]
     expected: TIMEOUT
 
-  [Number 0.2]
-    expected:
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
   [Number 0]
     expected: TIMEOUT
 
   [Number -0]
     expected: TIMEOUT
 
   [Number NaN]
     expected: TIMEOUT
@@ -240,9 +234,8 @@
   [Number -Infinity]
     expected: TIMEOUT
 
   [Number 9007199254740992]
     expected: TIMEOUT
 
   [Number -9007199254740992]
     expected: TIMEOUT
-
--- a/testing/web-platform/meta/workers/semantics/structured-clone/shared.html.ini
+++ b/testing/web-platform/meta/workers/semantics/structured-clone/shared.html.ini
@@ -217,315 +217,10 @@
     expected: TIMEOUT
 
   [Object with non-writable property]
     expected: TIMEOUT
 
   [Object with non-configurable property]
     expected: TIMEOUT
 
-  [Array primitives]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Object primitives]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Boolean true]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Boolean false]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Array Boolean objects]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Object Boolean objects]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [String empty string]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [String lone high surrogate]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [String lone low surrogate]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [String NUL]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [String astral character]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Array String objects]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Object String objects]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Number 0.2]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Number 0]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Number -0]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Number NaN]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Number Infinity]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [Number -Infinity]
-    expected:
-      if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
   [Number 9007199254740992]
     expected: TIMEOUT
-
-  [primitive undefined]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive null]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive true]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive false]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive string, empty string]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive string, lone high surrogate]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive string, lone low surrogate]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive string, NUL]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive string, astral character]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, 0.2]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, 0]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, -0]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, NaN]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, Infinity]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, -Infinity]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, 9007199254740992]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, -9007199254740992]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, 9007199254740994]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
-  [primitive number, -9007199254740994]
-    expected:
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -12386,168 +12386,25 @@
     "record_in_processes": ["main", "content"],
     "alert_emails": ["jcoppeard@mozilla.com"],
     "expires_in_version": "63",
     "kind": "categorical",
     "bug_numbers": [1430145],
     "labels": ["ClassicScript", "ModuleScript"],
     "description": "Record the kind of every script loaded in a document."
   },
-  "DOM_SCRIPT_SRC_ENCODING": {
-    "record_in_processes": ["main", "content"],
-    "alert_emails": ["dteller@mozilla.com"],
-    "expires_in_version": "61",
-    "kind": "count",
-    "keyed": true,
-    "bug_numbers": [1344152],
-    "description": "Note the encoding (e.g. 'UTF-8', 'windows-1252', 'ASCII') of each external <script> element that is successfully loaded and decoded."
-  },
   "DOM_SCRIPT_LOADING_SOURCE": {
     "record_in_processes": ["content"],
     "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
+    "expires_in_version": "never",
     "kind": "categorical",
     "bug_numbers": [1362114],
     "labels": ["Inline", "SourceFallback", "Source", "AltData"],
     "description": "Record the input from which the bytes are coming from, for each script in a document."
   },
-  "DOM_SCRIPT_INLINE_SIZE": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "exponential",
-    "low": 64,
-    "high": 16000000,
-    "n_buckets": 50,
-    "bug_numbers": [1362114],
-    "description": "Size (in number of characters) of each script which is inlined in a document."
-  },
-  "DOM_SCRIPT_SOURCE_SIZE": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "exponential",
-    "low": 64,
-    "high": 16000000,
-    "n_buckets": 50,
-    "bug_numbers": [1362114],
-    "description": "Size (in number of characters) of each script which is streamed in plain-text in a document."
-  },
-  "DOM_SCRIPT_BYTECODE_SIZE": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "exponential",
-    "low": 64,
-    "high": 16000000,
-    "n_buckets": 50,
-    "bug_numbers": [1362114],
-    "description": "Size (in number of bytes) of each script which is streamed in encoded-format in a document."
-  },
-  "DOM_SCRIPT_FETCH_COUNT": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "linear",
-    "low": 1,
-    "high": 100,
-    "n_buckets": 99,
-    "bug_numbers": [1362114],
-    "description": "For each script in a document, record the number of times it was requested since it got saved in the cache."
-  },
-  "DOM_SCRIPT_MAIN_THREAD_PARSE_EXEC_MS": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "exponential",
-    "high": 50000,
-    "n_buckets": 100,
-    "bug_numbers": [1362114],
-    "description": "Time, in milliseconds, needed to parse and execute a script (which might be encoded later) on the main thread."
-  },
-  "DOM_SCRIPT_MAIN_THREAD_PARSE_ENCODE_EXEC_MS": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "exponential",
-    "high": 50000,
-    "n_buckets": 100,
-    "bug_numbers": [1362114],
-    "description": "Time, in milliseconds, needed to parse, encode and execute a script on the main thread."
-  },
-  "DOM_SCRIPT_MAIN_THREAD_DECODE_EXEC_MS": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "exponential",
-    "high": 50000,
-    "n_buckets": 100,
-    "bug_numbers": [1362114],
-    "description": "Time, in milliseconds, needed to decode and execute a script on the main thread."
-  },
-  "DOM_SCRIPT_OFF_THREAD_PARSE_EXEC_MS": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "exponential",
-    "high": 50000,
-    "n_buckets": 100,
-    "bug_numbers": [1362114],
-    "description": "Time, in milliseconds, needed to parse off-main-thread and execute a script (which might be encoded later) on the main thread."
-  },
-  "DOM_SCRIPT_OFF_THREAD_PARSE_ENCODE_EXEC_MS": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "exponential",
-    "high": 50000,
-    "n_buckets": 100,
-    "bug_numbers": [1362114],
-    "description": "Time, in milliseconds, needed to parse off-main-thread, encode and execute a script on the main thread."
-  },
-  "DOM_SCRIPT_OFF_THREAD_DECODE_EXEC_MS": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "exponential",
-    "high": 50000,
-    "n_buckets": 100,
-    "bug_numbers": [1362114],
-    "description": "Time, in milliseconds, needed to decode off-main-thread and execute a script on the main thread."
-  },
-  "DOM_SCRIPT_ENCODING_MS_PER_DOCUMENT": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "linear",
-    "high": 64,
-    "n_buckets": 32,
-    "bug_numbers": [1362114],
-    "description": "Time, in milliseconds, needed to encode all scripts in a document."
-  },
-  "DOM_SCRIPT_ENCODING_STATUS": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "categorical",
-    "bug_numbers": [1362114],
-    "labels": ["EncodingFailure", "BufferTooLarge", "OpenFailure", "WriteFailure", "CloseFailure", "EncodingSuccess"],
-    "description": "Record the failure reasons of the JavaScript Start-up Bytecode Cache encoder."
-  },
-  "DOM_SCRIPT_EVAL_PER_DOCUMENT": {
-    "record_in_processes": ["content"],
-    "alert_emails": ["nicolas.b.pierron@mozilla.com"],
-    "expires_in_version": "62",
-    "kind": "linear",
-    "low": 1,
-    "high": 200,
-    "n_buckets": 50,
-    "bug_numbers": [1362114],
-    "description": "Number of script tags evaluated per document."
-  },
   "DOM_SCRIPT_PRELOAD_RESULT": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["jcoppeard@mozilla.com"],
     "expires_in_version": "63",
     "kind": "categorical",
     "bug_numbers": [1430145],
     "labels": ["Used", "RejectedByPolicy", "RequestMismatch", "LoadError", "NotUsed"],
     "description": "Whether a preloaded script was used or the reason it was not used."
--- a/toolkit/components/telemetry/histogram-whitelists.json
+++ b/toolkit/components/telemetry/histogram-whitelists.json
@@ -1546,17 +1546,16 @@
     "DEVTOOLS_STORAGE_OPENED_COUNT",
     "DEVTOOLS_STYLEEDITOR_OPENED_COUNT",
     "DEVTOOLS_TOOLBOX_OPENED_COUNT",
     "DEVTOOLS_WEBAUDIOEDITOR_OPENED_COUNT",
     "DEVTOOLS_WEBCONSOLE_OPENED_COUNT",
     "DEVTOOLS_WEBIDE_IMPORT_PROJECT_COUNT",
     "DEVTOOLS_WEBIDE_NEW_PROJECT_COUNT",
     "DEVTOOLS_WEBIDE_OPENED_COUNT",
-    "DOM_SCRIPT_SRC_ENCODING",
     "ENABLE_PRIVILEGE_EVER_CALLED",
     "FENNEC_DISTRIBUTION_REFERRER_INVALID",
     "FENNEC_ORBOT_INSTALLED",
     "FENNEC_RESTORING_ACTIVITY",
     "FENNEC_SESSIONSTORE_ALL_FILES_DAMAGED",
     "FENNEC_SESSIONSTORE_DAMAGED_SESSION_FILE",
     "FENNEC_SESSIONSTORE_RESTORING_FROM_BACKUP",
     "FENNEC_SYNC11_MIGRATIONS_COMPLETED",