Merge autoland to central, a=merge CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 19 Jul 2017 16:32:03 -0700
changeset 418398 a8885191775ad1f655d2826f8f8e943a9a985f43
parent 418341 4b32e7ce740eaf6434180bc9e44731dab0aa67cc (current diff)
parent 418397 22e24b1ada9431c21c7f1f8a950d68ec94842c83 (diff)
child 418466 eb1d92b2b6a4161492561250f51bae5bafeda68a
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to central, a=merge CLOSED TREE MozReview-Commit-ID: 9RON7kHON0g
browser/modules/FullZoomUI.jsm
testing/web-platform/meta/cssom/selectorSerialize.html.ini
third_party/python/voluptuous/COPYING
third_party/python/voluptuous/MANIFEST.in
third_party/python/voluptuous/PKG-INFO
third_party/python/voluptuous/README.md
third_party/python/voluptuous/README.rst
third_party/python/voluptuous/setup.cfg
third_party/python/voluptuous/setup.py
third_party/python/voluptuous/tests.md
third_party/python/voluptuous/voluptuous.py
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -909,16 +909,24 @@ pref("browser.sessionstore.debug.no_auto
 // Forget closed windows/tabs after two weeks
 pref("browser.sessionstore.cleanup.forget_closed_after", 1209600000);
 // Maximum number of bytes of DOMSessionStorage data we collect per origin.
 pref("browser.sessionstore.dom_storage_limit", 2048);
 
 // allow META refresh by default
 pref("accessibility.blockautorefresh", false);
 
+// Whether useAsyncTransactions is enabled or not.
+// Currently we only enable them for nightly.
+#ifdef NIGHTLY_BUILD
+pref("browser.places.useAsyncTransactions", true);
+#else
+pref("browser.places.useAsyncTransactions", false);
+#endif
+
 // Whether history is enabled or not.
 pref("places.history.enabled", true);
 
 // the (maximum) number of the recent visits to sample
 // when calculating frecency
 pref("places.frecency.numVisits", 10);
 
 // buckets (in days) for frecency calculation
--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -61,16 +61,22 @@ function init(aEvent) {
       relNotesLink.href = relNotesURL;
       relNotesLink.hidden = false;
     }
   }
 
   if (AppConstants.MOZ_UPDATER) {
     gAppUpdater = new appUpdater();
 
+    let button = gAppUpdater.updateDeck.selectedPanel.querySelector("button");
+    if (button && (!document.commandDispatcher.focusedElement || // don't steal the focus
+                   document.commandDispatcher.focusedElement.localName == "button")) { // except from the other buttons
+      button.focus();
+    }
+
     let channelLabel = document.getElementById("currentChannel");
     let currentChannelText = document.getElementById("currentChannelText");
     channelLabel.value = UpdateUtils.UpdateChannel;
     if (/^release($|\-)/.test(channelLabel.value))
         currentChannelText.hidden = true;
   }
 
   if (AppConstants.platform == "macosx") {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -33,17 +33,17 @@ XPCOMUtils.defineLazyGetter(this, "exten
           LoginManagerParent:false, NewTabUtils:false, PageThumbs:false,
           PluralForm:false, Preferences:false, PrivateBrowsingUtils:false,
           ProcessHangMonitor:false, PromiseUtils:false, ReaderMode:false,
           ReaderParent:false, RecentWindow:false, SessionStore:false,
           ShortcutUtils:false, SimpleServiceDiscovery:false, SitePermissions:false,
           Social:false, TabCrashHandler:false, Task:false, TelemetryStopwatch:false,
           Translation:false, UITour:false, UpdateUtils:false, Weave:false,
           WebNavigationFrames: false, fxAccounts:false, gDevTools:false,
-          gDevToolsBrowser:false, webrtcUI:false, FullZoomUI:false,
+          gDevToolsBrowser:false, webrtcUI:false, ZoomUI:false,
           Marionette:false,
  */
 
 /**
  * IF YOU ADD OR REMOVE FROM THIS LIST, PLEASE UPDATE THE LIST ABOVE AS WELL.
  * XXX Bug 1325373 is for making eslint detect these automatically.
  */
 [
@@ -54,17 +54,16 @@ XPCOMUtils.defineLazyGetter(this, "exten
   ["CastingApps", "resource:///modules/CastingApps.jsm"],
   ["CharsetMenu", "resource://gre/modules/CharsetMenu.jsm"],
   ["Color", "resource://gre/modules/Color.jsm"],
   ["ContentSearch", "resource:///modules/ContentSearch.jsm"],
   ["Deprecated", "resource://gre/modules/Deprecated.jsm"],
   ["E10SUtils", "resource:///modules/E10SUtils.jsm"],
   ["ExtensionsUI", "resource:///modules/ExtensionsUI.jsm"],
   ["FormValidationHandler", "resource:///modules/FormValidationHandler.jsm"],
-  ["FullZoomUI", "resource:///modules/FullZoomUI.jsm"],
   ["GMPInstallManager", "resource://gre/modules/GMPInstallManager.jsm"],
   ["LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm"],
   ["Log", "resource://gre/modules/Log.jsm"],
   ["LoginManagerParent", "resource://gre/modules/LoginManagerParent.jsm"],
   ["NewTabUtils", "resource://gre/modules/NewTabUtils.jsm"],
   ["PageThumbs", "resource://gre/modules/PageThumbs.jsm"],
   ["PluralForm", "resource://gre/modules/PluralForm.jsm"],
   ["Preferences", "resource://gre/modules/Preferences.jsm"],
@@ -86,16 +85,17 @@ XPCOMUtils.defineLazyGetter(this, "exten
   ["UITour", "resource:///modules/UITour.jsm"],
   ["UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"],
   ["Weave", "resource://services-sync/main.js"],
   ["WebNavigationFrames", "resource://gre/modules/WebNavigationFrames.js"],
   ["fxAccounts", "resource://gre/modules/FxAccounts.jsm"],
   ["gDevTools", "resource://devtools/client/framework/gDevTools.jsm"],
   ["gDevToolsBrowser", "resource://devtools/client/framework/gDevTools.jsm"],
   ["webrtcUI", "resource:///modules/webrtcUI.jsm"],
+  ["ZoomUI", "resource:///modules/ZoomUI.jsm"],
 ].forEach(([name, resource]) => XPCOMUtils.defineLazyModuleGetter(this, name, resource));
 
 XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
   "resource://gre/modules/SafeBrowsing.jsm");
 
 if (AppConstants.MOZ_CRASHREPORTER) {
   XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter",
     "resource:///modules/ContentCrashHandlers.jsm");
@@ -1268,17 +1268,17 @@ var gBrowserInit = {
     LanguageDetectionListener.init();
     BrowserOnClick.init();
     FeedHandler.init();
     CompactTheme.init();
     AboutPrivateBrowsingListener.init();
     TrackingProtection.init();
     RefreshBlocker.init();
     CaptivePortalWatcher.init();
-    FullZoomUI.init(window);
+    ZoomUI.init(window);
 
     let mm = window.getGroupMessageManager("browsers");
     mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
     mm.loadFrameScript("chrome://browser/content/content.js", true);
     mm.loadFrameScript("chrome://browser/content/content-UITour.js", true);
     mm.loadFrameScript("chrome://global/content/manifestMessages.js", true);
 
     // initialize observers and listeners
--- a/browser/base/content/test/general/browser_bookmark_popup.js
+++ b/browser/base/content/test/general/browser_bookmark_popup.js
@@ -10,16 +10,23 @@
 
 let bookmarkPanel = document.getElementById("editBookmarkPanel");
 let bookmarkStar = AppConstants.MOZ_PHOTON_THEME ? BookmarkingUI.star : BookmarkingUI.button;
 let bookmarkPanelTitle = document.getElementById("editBookmarkPanelTitle");
 let editBookmarkPanelRemoveButtonRect;
 
 StarUI._closePanelQuickForTesting = true;
 
+add_task(async function setup() {
+  bookmarkPanel.setAttribute("animate", false);
+  registerCleanupFunction(() => {
+    bookmarkPanel.removeAttribute("animate");
+  });
+})
+
 async function test_bookmarks_popup({isNewBookmark, popupShowFn, popupEditFn,
                                 shouldAutoClose, popupHideFn, isBookmarkRemoved}) {
   await BrowserTestUtils.withNewTab({gBrowser, url: "about:home"}, async function(browser) {
     try {
       if (!isNewBookmark) {
         await PlacesUtils.bookmarks.insert({
           parentGuid: PlacesUtils.bookmarks.unfiledGuid,
           url: "about:home",
@@ -377,17 +384,17 @@ add_task(async function enter_on_remove_
 add_task(async function mouse_hovering_panel_should_prevent_autoclose() {
   if (AppConstants.platform != "win") {
     // This test requires synthesizing native mouse movement which is
     // best supported on Windows.
     return;
   }
   await test_bookmarks_popup({
     isNewBookmark: true,
-    async popupShowFn(browser) {
+    async popupShowFn() {
       await new Promise(resolve => {
         EventUtils.synthesizeNativeMouseMove(
           document.documentElement,
           editBookmarkPanelRemoveButtonRect.left,
           editBookmarkPanelRemoveButtonRect.top,
           resolve);
       });
       EventUtils.synthesizeKey("D", {accelKey: true}, window);
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -24,18 +24,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillHandler",
                                   "resource://formautofill/FormAutofillHandler.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FormLikeFactory",
                                   "resource://gre/modules/FormLikeFactory.jsm");
 
 const formFillController = Cc["@mozilla.org/satchel/form-fill-controller;1"]
                              .getService(Ci.nsIFormFillController);
 
-const AUTOFILL_FIELDS_THRESHOLD = 3;
-
 // Register/unregister a constructor as a factory.
 function AutocompleteFactory() {}
 AutocompleteFactory.prototype = {
   register(targetConstructor) {
     let proto = targetConstructor.prototype;
     this._classID = proto.classID;
 
     let factory = XPCOMUtils._getFactory(targetConstructor);
@@ -360,17 +358,17 @@ var FormAutofillContent = {
 
     let handler = this._formsDetails.get(formElement);
     if (!handler) {
       this.log.debug("Form element could not map to an existing handler");
       return true;
     }
 
     let pendingAddress = handler.createProfile();
-    if (Object.keys(pendingAddress).length < AUTOFILL_FIELDS_THRESHOLD) {
+    if (Object.keys(pendingAddress).length < FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD) {
       this.log.debug(`Not saving since there are only ${Object.keys(pendingAddress).length} usable fields`);
       return true;
     }
 
     this._onFormSubmit({
       address: {
         guid: handler.filledProfileGUID,
         record: pendingAddress,
@@ -471,25 +469,33 @@ var FormAutofillContent = {
       return;
     }
 
     formHandler.collectFormFields();
 
     this._formsDetails.set(formHandler.form.rootElement, formHandler);
     this.log.debug("Adding form handler to _formsDetails:", formHandler);
 
-    if (formHandler.fieldDetails.length < AUTOFILL_FIELDS_THRESHOLD) {
-      this.log.debug("Ignoring form since it has only", formHandler.fieldDetails.length,
+    if (formHandler.isValidAddressForm) {
+      formHandler.addressFieldDetails.forEach(
+        detail => this._markAsAutofillField(detail.elementWeakRef.get())
+      );
+    } else {
+      this.log.debug("Ignoring address related fields since it has only",
+                     formHandler.addressFieldDetails.length,
                      "field(s)");
-      return;
     }
 
-    formHandler.fieldDetails.forEach(detail =>
-      this._markAsAutofillField(detail.elementWeakRef.get())
-    );
+    if (formHandler.isValidCreditCardForm) {
+      formHandler.creditCardFieldDetails.forEach(
+        detail => this._markAsAutofillField(detail.elementWeakRef.get())
+      );
+    } else {
+      this.log.debug("Ignoring credit card related fields since it's without credit card number field");
+    }
   },
 
   _markAsAutofillField(field) {
     // Since Form Autofill popup is only for input element, any non-Input
     // element should be excluded here.
     if (!field || !(field instanceof Ci.nsIDOMHTMLInputElement)) {
       return;
     }
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -52,16 +52,36 @@ FormAutofillHandler.prototype = {
    * the same exact combination of these values.
    *
    * A direct reference to the associated element cannot be sent to the user
    * interface because processing may be done in the parent process.
    */
   fieldDetails: null,
 
   /**
+   * Similiar to `fieldDetails`, and `addressFieldDetails` contains the address
+   * records only.
+   */
+  addressFieldDetails: null,
+
+  /**
+   * Similiar to `fieldDetails`, and `creditCardFieldDetails` contains the
+   * Credit Card records only.
+   */
+  creditCardFieldDetails: null,
+
+  get isValidAddressForm() {
+    return this.addressFieldDetails.length > FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD;
+  },
+
+  get isValidCreditCardForm() {
+    return this.creditCardFieldDetails.some(i => i.fieldName == "cc-number");
+  },
+
+  /**
    * String of the filled profile's guid.
    */
   filledProfileGUID: null,
 
   /**
    * A WindowUtils reference of which Window the form belongs
    */
   winUtils: null,
@@ -90,16 +110,23 @@ FormAutofillHandler.prototype = {
    * Set fieldDetails from the form about fields that can be autofilled.
    */
   collectFormFields() {
     this._cacheValue.allFieldNames = null;
     this._formFieldCount = this.form.elements.length;
     let fieldDetails = FormAutofillHeuristics.getFormInfo(this.form);
     this.fieldDetails = fieldDetails ? fieldDetails : [];
     log.debug("Collected details on", this.fieldDetails.length, "fields");
+
+    this.addressFieldDetails = this.fieldDetails.filter(
+      detail => FormAutofillUtils.isAddressField(detail.fieldName)
+    );
+    this.creditCardFieldDetails = this.fieldDetails.filter(
+      detail => FormAutofillUtils.isCreditCardField(detail.fieldName)
+    );
   },
 
   getFieldDetailByName(fieldName) {
     return this.fieldDetails.find(detail => detail.fieldName == fieldName);
   },
 
   _cacheValue: {
     allFieldNames: null,
@@ -162,17 +189,17 @@ FormAutofillHandler.prototype = {
    *        A profile to be filled in.
    * @param {Object} focusedInput
    *        A focused input element which is skipped for filling.
    */
   autofillFormFields(profile, focusedInput) {
     log.debug("profile in autofillFormFields:", profile);
 
     this.filledProfileGUID = profile.guid;
-    for (let fieldDetail of this.fieldDetails) {
+    for (let fieldDetail of this.addressFieldDetails) {
       // Avoid filling field value in the following cases:
       // 1. the focused input which is filled in FormFillController.
       // 2. a non-empty input field
       // 3. the invalid value set
       // 4. value already chosen in select element
 
       let element = fieldDetail.elementWeakRef.get();
       if (!element) {
@@ -223,17 +250,17 @@ FormAutofillHandler.prototype = {
     log.debug("register change handler for filled form:", this.form);
     const onChangeHandler = e => {
       let hasFilledFields;
 
       if (!e.isTrusted) {
         return;
       }
 
-      for (let fieldDetail of this.fieldDetails) {
+      for (let fieldDetail of this.addressFieldDetails) {
         let element = fieldDetail.elementWeakRef.get();
 
         if (!element) {
           return;
         }
 
         if (e.target == element || (e.target == element.form && e.type == "reset")) {
           this.changeFieldState(fieldDetail, "NORMAL");
@@ -258,17 +285,17 @@ FormAutofillHandler.prototype = {
    * Populates result to the preview layers with given profile.
    *
    * @param {Object} profile
    *        A profile to be previewed with
    */
   previewFormFields(profile) {
     log.debug("preview profile in autofillFormFields:", profile);
 
-    for (let fieldDetail of this.fieldDetails) {
+    for (let fieldDetail of this.addressFieldDetails) {
       let element = fieldDetail.elementWeakRef.get();
       let value = profile[fieldDetail.fieldName] || "";
 
       // Skip the field that is null
       if (!element) {
         continue;
       }
 
@@ -290,17 +317,17 @@ FormAutofillHandler.prototype = {
   },
 
   /**
    * Clear preview text and background highlight of all fields.
    */
   clearPreviewedFormFields() {
     log.debug("clear previewed fields in:", this.form);
 
-    for (let fieldDetail of this.fieldDetails) {
+    for (let fieldDetail of this.addressFieldDetails) {
       let element = fieldDetail.elementWeakRef.get();
       if (!element) {
         log.warn(fieldDetail.fieldName, "is unreachable");
         continue;
       }
 
       element.previewValue = "";
 
@@ -355,17 +382,17 @@ FormAutofillHandler.prototype = {
    * Return the profile that is converted from fieldDetails and only non-empty fields
    * are included.
    *
    * @returns {Object} The new profile that convert from details with trimmed result.
    */
   createProfile() {
     let profile = {};
 
-    this.fieldDetails.forEach(detail => {
+    this.addressFieldDetails.forEach(detail => {
       let element = detail.elementWeakRef.get();
       // Remove the unnecessary spaces
       let value = element && element.value.trim();
       if (!value) {
         return;
       }
 
       profile[detail.fieldName] = value;
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -8,16 +8,18 @@ this.EXPORTED_SYMBOLS = ["FormAutofillUt
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 const ADDRESS_REFERENCES = "chrome://formautofill/content/addressReferences.js";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 this.FormAutofillUtils = {
+  get AUTOFILL_FIELDS_THRESHOLD() { return 3; },
+
   _fieldNameInfo: {
     "name": "name",
     "given-name": "name",
     "additional-name": "name",
     "family-name": "name",
     "organization": "organization",
     "street-address": "address",
     "address-line1": "address",
--- a/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
+++ b/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
@@ -25,15 +25,21 @@
     <p><label><input type="text" name="address-line2" /></label></p>
     <p><label><input type="text" id="B_address-line3" name="address-line3" /></label></p>
     <p><label>City: <input type="text" name="address-level2" /></label></p>
     <p><label>State: <select id="B_address-level1" ></select></label></p>
     <p><input type="text" id="B_postal-code" name="postal-code" /></p>
     <p><label>Country: <select multiple id="B_country" name="country" ></select></label></p>
     <p><label>Telephone: <input id="B_tel" name="tel" /></label></p>
     <p><label>Email: <input type="text" id="B_email" name="email" /></label></p>
+    <hr>
+    <p><label>cc-number <input type="text" id="B_cc-number" autocomplete="cc-number" /></label></p>
+    <p><label>cc-name <input type="text" id="B_cc-name" autocomplete="cc-name" /></label></p>
+    <p><label>cc-exp-month <input type="text" id="B_cc-exp-month" autocomplete="cc-exp-month" /></label></p>
+    <p><label>cc-exp-year <input type="text" id="B_cc-exp-year" autocomplete="cc-exp-year" /></label></p>
+    <hr>
     <p><input type="submit" /></p>
     <p><button type="reset">Reset</button></p>
   </form>
 
 </body>
 </html>
 
--- a/browser/extensions/formautofill/test/unit/heuristics/test_basic.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/test_basic.js
@@ -22,13 +22,17 @@ runHeuristicsTest([
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line3"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
       ],
     ],
   },
 ], "../../fixtures/");
 
--- a/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
@@ -7,17 +7,17 @@
 Cu.import("resource://formautofill/FormAutofillHandler.jsm");
 
 const TESTCASES = [
   {
     description: "Form without autocomplete property",
     document: `<form><input id="given-name"><input id="family-name">
                <input id="street-addr"><input id="city"><select id="country"></select>
                <input id='email'><input id="tel"></form>`,
-    fieldDetails: [],
+    addressFieldDetails: [],
     profileData: {},
     expectedResult: {
       "street-addr": "",
       "city": "",
       "country": "",
       "email": "",
       "tel": "",
     },
@@ -29,17 +29,17 @@ const TESTCASES = [
                <input id="street-addr" autocomplete="street-address">
                <input id="city" autocomplete="address-level2">
                <select id="country" autocomplete="country">
                  <option/>
                  <option value="US">United States</option>
                </select>
                <input id="email" autocomplete="email">
                <input id="tel" autocomplete="tel"></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "email", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "tel", "element": {}},
     ],
@@ -67,17 +67,17 @@ const TESTCASES = [
                <input id="street-addr" autocomplete="shipping street-address">
                <input id="city" autocomplete="shipping address-level2">
                <select id="country" autocomplete="shipping country">
                  <option/>
                  <option value="US">United States</option>
                </select>
                <input id='email' autocomplete="shipping email">
                <input id="tel" autocomplete="shipping tel"></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "email", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel", "element": {}},
     ],
@@ -101,17 +101,17 @@ const TESTCASES = [
     description: "Form with autocomplete properties and profile is partly matched",
     document: `<form><input id="given-name" autocomplete="shipping given-name">
                <input id="family-name" autocomplete="shipping family-name">
                <input id="street-addr" autocomplete="shipping street-address">
                <input id="city" autocomplete="shipping address-level2">
                <input id="country" autocomplete="shipping country">
                <input id='email' autocomplete="shipping email">
                <input id="tel" autocomplete="shipping tel"></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "email", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel", "element": {}},
     ],
@@ -135,17 +135,17 @@ const TESTCASES = [
     description: "Form with autocomplete properties but mismatched",
     document: `<form><input id="given-name" autocomplete="shipping given-name">
                <input id="family-name" autocomplete="shipping family-name">
                <input id="street-addr" autocomplete="billing street-address">
                <input id="city" autocomplete="billing address-level2">
                <input id="country" autocomplete="billing country">
                <input id='email' autocomplete="shipping email">
                <input id="tel" autocomplete="shipping tel"></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "email", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "organization", "element": null},
@@ -174,17 +174,17 @@ const TESTCASES = [
                  <option value="US">United States</option>
                </select>
                <select id="state" autocomplete="shipping address-level1">
                  <option value=""></option>
                  <option value="CA">California</option>
                  <option value="WA">Washington</option>
                </select>
                </form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level1", "element": {}},
     ],
     profileData: {
       "guid": "123",
       "country": "US",
       "address-level1": "CA",
     },
@@ -201,17 +201,17 @@ const TESTCASES = [
                  <option value="US">United States</option>
                </select>
                <select id="state" autocomplete="shipping address-level1">
                  <option value=""></option>
                  <option value="CA">California</option>
                  <option value="WA">Washington</option>
                </select>
                </form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level1", "element": {}},
     ],
     profileData: {
       "guid": "123",
       "country": "United States",
       "address-level1": "California",
     },
@@ -230,17 +230,17 @@ const TESTCASES_INPUT_UNCHANGED = [
                  <option value="US">United States</option>
                </select>
                <select id="state" autocomplete="shipping address-level1">
                  <option value=""></option>
                  <option value="CA">California</option>
                  <option value="WA">Washington</option>
                </select>
                </form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level1", "element": {}},
     ],
     profileData: {
       "guid": "123",
       "country": "US",
       "address-level1": "unknown state",
     },
@@ -253,17 +253,17 @@ const TESTCASES_INPUT_UNCHANGED = [
 
 const TESTCASES_US_STATES = [
   {
     description: "Form with US states select elements; with lower case state key",
     document: `<form><select id="state" autocomplete="shipping address-level1">
                  <option value=""></option>
                  <option value="CA">California</option>
                </select></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level1", "element": {}},
     ],
     profileData: {
       "guid": "123",
       "country": "US",
       "address-level1": "ca",
     },
     expectedResult: {
@@ -271,17 +271,17 @@ const TESTCASES_US_STATES = [
     },
   },
   {
     description: "Form with US states select elements; with state name and extra spaces",
     document: `<form><select id="state" autocomplete="shipping address-level1">
                  <option value=""></option>
                  <option value="CA">CA</option>
                </select></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level1", "element": {}},
     ],
     profileData: {
       "guid": "123",
       "country": "US",
       "address-level1": " California ",
     },
     expectedResult: {
@@ -289,17 +289,17 @@ const TESTCASES_US_STATES = [
     },
   },
   {
     description: "Form with US states select elements; with partial state key match",
     document: `<form><select id="state" autocomplete="shipping address-level1">
                  <option value=""></option>
                  <option value="US-WA">WA-Washington</option>
                </select></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level1", "element": {}},
     ],
     profileData: {
       "guid": "123",
       "country": "US",
       "address-level1": "WA",
     },
     expectedResult: {
@@ -317,18 +317,18 @@ function do_test(testcases, testFn) {
 
         let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
                                                   testcase.document);
         let form = doc.querySelector("form");
         let formLike = FormLikeFactory.createFromForm(form);
         let handler = new FormAutofillHandler(formLike);
         let promises = [];
 
-        handler.fieldDetails = testcase.fieldDetails;
-        handler.fieldDetails.forEach((field, index) => {
+        handler.addressFieldDetails = testcase.addressFieldDetails;
+        handler.addressFieldDetails.forEach((field, index) => {
           let element = doc.querySelectorAll("input, select")[index];
           field.elementWeakRef = Cu.getWeakReference(element);
           if (!testcase.profileData[field.fieldName]) {
             // Avoid waiting for `change` event of a input with a blank value to
             // be filled.
             return;
           }
           promises.push(...testFn(testcase, element));
--- a/browser/extensions/formautofill/test/unit/test_collectFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_collectFormFields.js
@@ -7,112 +7,202 @@
 Cu.import("resource://formautofill/FormAutofillHandler.jsm");
 
 const TESTCASES = [
   {
     description: "Form without autocomplete property",
     document: `<form><input id="given-name"><input id="family-name">
                <input id="street-addr"><input id="city"><select id="country"></select>
                <input id='email'><input id="tel"></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
     ],
+    creditCardFieldDetails: [],
+    isValidForm: {
+      address: true,
+      creditCard: false,
+    },
     ids: ["given-name", "family-name", "street-addr", "city", "country", "email", "tel"],
   },
   {
-    description: "Form with autocomplete properties and 1 token",
-    document: `<form><input id="given-name" autocomplete="given-name">
+    description: "An address and credit card form with autocomplete properties and 1 token",
+    document: `<form>
+               <input id="given-name" autocomplete="given-name">
                <input id="family-name" autocomplete="family-name">
                <input id="street-addr" autocomplete="street-address">
                <input id="city" autocomplete="address-level2">
                <select id="country" autocomplete="country"></select>
                <input id="email" autocomplete="email">
-               <input id="tel" autocomplete="tel"></form>`,
-    fieldDetails: [
+               <input id="tel" autocomplete="tel">
+               <input id="cc-number" autocomplete="cc-number">
+               <input id="cc-name" autocomplete="cc-name">
+               <input id="cc-exp-month" autocomplete="cc-exp-month">
+               <input id="cc-exp-year" autocomplete="cc-exp-year">
+               </form>`,
+    addressFieldDetails: [
       {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
     ],
+    creditCardFieldDetails: [
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+    ],
+    isValidForm: {
+      address: true,
+      creditCard: true,
+    },
   },
   {
-    description: "Form with autocomplete properties and 2 tokens",
+    description: "An address form with autocomplete properties and 2 tokens",
     document: `<form><input id="given-name" autocomplete="shipping given-name">
                <input id="family-name" autocomplete="shipping family-name">
                <input id="street-addr" autocomplete="shipping street-address">
                <input id="city" autocomplete="shipping address-level2">
                <input id="country" autocomplete="shipping country">
                <input id='email' autocomplete="shipping email">
                <input id="tel" autocomplete="shipping tel"></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "email"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel"},
     ],
+    creditCardFieldDetails: [],
+    isValidForm: {
+      address: true,
+      creditCard: false,
+    },
   },
   {
     description: "Form with autocomplete properties and profile is partly matched",
     document: `<form><input id="given-name" autocomplete="shipping given-name">
                <input id="family-name" autocomplete="shipping family-name">
                <input id="street-addr" autocomplete="shipping street-address">
                <input autocomplete="shipping address-level2">
                <select autocomplete="shipping country"></select>
                <input id='email' autocomplete="shipping email">
                <input id="tel" autocomplete="shipping tel"></form>`,
-    fieldDetails: [
+    addressFieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "email"},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel"},
     ],
+    creditCardFieldDetails: [],
+    isValidForm: {
+      address: true,
+      creditCard: false,
+    },
+  },
+  {
+    description: "It's a valid address and credit card form.",
+    document: `<form>
+               <input id="given-name" autocomplete="shipping given-name">
+               <input id="family-name" autocomplete="shipping family-name">
+               <input id="street-addr" autocomplete="shipping street-address">
+               <input id="city" autocomplete="shipping address-level2">
+               <input id="cc-number" autocomplete="shipping cc-number">
+               </form>`,
+    addressFieldDetails: [
+      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name"},
+      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name"},
+      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address"},
+      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2"},
+    ],
+    creditCardFieldDetails: [
+      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "cc-number"},
+    ],
+    isValidForm: {
+      address: true,
+      creditCard: true,
+    },
+  },
+  {
+    description: "It's an invalid address and credit form.",
+    document: `<form>
+               <input id="given-name" autocomplete="shipping given-name">
+               <input autocomplete="shipping address-level2">
+               <select autocomplete="shipping country"></select>
+               <input id="cc-name" autocomplete="cc-name">
+               <input id="cc-exp-month" autocomplete="cc-exp-month">
+               <input id="cc-exp-year" autocomplete="cc-exp-year">
+               </form>`,
+    addressFieldDetails: [
+      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name"},
+      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2"},
+      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country"},
+    ],
+    creditCardFieldDetails: [
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+    ],
+    isValidForm: {
+      address: false,
+      creditCard: false,
+    },
   },
 ];
 
 for (let tc of TESTCASES) {
   (function() {
     let testcase = tc;
     add_task(async function() {
       do_print("Starting testcase: " + testcase.description);
 
       let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
                                                 testcase.document);
       let form = doc.querySelector("form");
       let formLike = FormLikeFactory.createFromForm(form);
 
-      testcase.fieldDetails.forEach((detail, index) => {
+      Array.of(
+        ...testcase.addressFieldDetails,
+        ...testcase.creditCardFieldDetails
+      ).forEach((detail, index) => {
         let elementRef;
         if (testcase.ids && testcase.ids[index]) {
           elementRef = doc.getElementById(testcase.ids[index]);
         } else {
           elementRef = doc.querySelector("*[autocomplete*='" + detail.fieldName + "']");
         }
         detail.elementWeakRef = Cu.getWeakReference(elementRef);
       });
       let handler = new FormAutofillHandler(formLike);
 
       handler.collectFormFields();
 
-      handler.fieldDetails.forEach((detail, index) => {
-        Assert.equal(detail.section, testcase.fieldDetails[index].section);
-        Assert.equal(detail.addressType, testcase.fieldDetails[index].addressType);
-        Assert.equal(detail.contactType, testcase.fieldDetails[index].contactType);
-        Assert.equal(detail.fieldName, testcase.fieldDetails[index].fieldName);
-        Assert.equal(detail.elementWeakRef.get(), testcase.fieldDetails[index].elementWeakRef.get());
-      });
+      function verifyDetails(handlerDetails, testCaseDetails) {
+        handlerDetails.forEach((detail, index) => {
+          Assert.equal(detail.section, testCaseDetails[index].section);
+          Assert.equal(detail.addressType, testCaseDetails[index].addressType);
+          Assert.equal(detail.contactType, testCaseDetails[index].contactType);
+          Assert.equal(detail.fieldName, testCaseDetails[index].fieldName);
+          Assert.equal(detail.elementWeakRef.get(), testCaseDetails[index].elementWeakRef.get());
+        });
+      }
+
+      verifyDetails(handler.addressFieldDetails, testcase.addressFieldDetails);
+      verifyDetails(handler.creditCardFieldDetails, testcase.creditCardFieldDetails);
+
+      Assert.equal(handler.isValidAddressForm, testcase.isValidForm.address, "Valid Address Form Checking");
+      Assert.equal(handler.isValidCreditCardForm, testcase.isValidForm.creditCard, "Valid Credit Card Form Checking");
     });
   })();
 }
--- a/browser/extensions/formautofill/test/unit/test_getInfo.js
+++ b/browser/extensions/formautofill/test/unit/test_getInfo.js
@@ -95,30 +95,30 @@ const TESTCASES = [
       contactType: "",
     },
   },
   {
     description: "2 address line inputs",
     document: `<label for="targetElement">street</label>
                <input id="targetElement" type="text">`,
     elementId: "targetElement",
-    fieldDetails: [{fieldName: "address-line1"}],
+    addressFieldDetails: [{fieldName: "address-line1"}],
     expectedReturnValue: {
       fieldName: "address-line2",
       section: "",
       addressType: "",
       contactType: "",
     },
   },
   {
     description: "3 address line inputs",
     document: `<label for="targetElement">street</label>
                <input id="targetElement" type="text">`,
     elementId: "targetElement",
-    fieldDetails: [
+    addressFieldDetails: [
       {fieldName: "address-line1"},
       {fieldName: "address-line2"},
     ],
     expectedReturnValue: {
       fieldName: "address-line3",
       section: "",
       addressType: "",
       contactType: "",
@@ -213,13 +213,13 @@ const TESTCASES = [
 TESTCASES.forEach(testcase => {
   add_task(async function() {
     do_print("Starting testcase: " + testcase.description);
 
     let doc = MockDocument.createTestDocument(
       "http://localhost:8080/test/", testcase.document);
 
     let element = doc.getElementById(testcase.elementId);
-    let value = FormAutofillHeuristics.getInfo(element, testcase.fieldDetails);
+    let value = FormAutofillHeuristics.getInfo(element, testcase.addressFieldDetails);
 
     Assert.deepEqual(value, testcase.expectedReturnValue);
   });
 });
rename from browser/modules/FullZoomUI.jsm
rename to browser/modules/ZoomUI.jsm
--- a/browser/modules/FullZoomUI.jsm
+++ b/browser/modules/ZoomUI.jsm
@@ -1,26 +1,28 @@
 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-this.EXPORTED_SYMBOLS = [ "FullZoomUI" ];
+this.EXPORTED_SYMBOLS = [ "ZoomUI" ];
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 
-var FullZoomUI = {
+var ZoomUI = {
   init(aWindow) {
     aWindow.addEventListener("EndSwapDocShells", onEndSwapDocShells, true);
-    aWindow.addEventListener("FullZoomChange", onFullZoomChange);
+    aWindow.addEventListener("FullZoomChange", onZoomChange);
+    aWindow.addEventListener("TextZoomChange", onZoomChange);
     aWindow.addEventListener("unload", () => {
       aWindow.removeEventListener("EndSwapDocShells", onEndSwapDocShells, true);
-      aWindow.removeEventListener("FullZoomChange", onFullZoomChange);
+      aWindow.removeEventListener("FullZoomChange", onZoomChange);
+      aWindow.removeEventListener("TextZoomChange", onZoomChange);
     }, {once: true});
   },
 }
 
 function fullZoomLocationChangeObserver(aSubject, aTopic) {
   // If the tab was the last one in its window and has been dragged to another
   // window, the original browser's window will be unavailable here. Since that
   // window is closing, we can just ignore this notification.
@@ -30,17 +32,17 @@ function fullZoomLocationChangeObserver(
   updateZoomUI(aSubject, false);
 }
 Services.obs.addObserver(fullZoomLocationChangeObserver, "browser-fullZoom:location-change");
 
 function onEndSwapDocShells(event) {
   updateZoomUI(event.originalTarget);
 }
 
-function onFullZoomChange(event) {
+function onZoomChange(event) {
   let browser;
   if (event.target.nodeType == event.target.DOCUMENT_NODE) {
     // In non-e10s, the event is dispatched on the contentDocument
     // so we need to jump through some hoops to get to the <xul:browser>.
     let gBrowser = event.currentTarget.gBrowser;
     let topDoc = event.target.defaultView.top.document;
     browser = gBrowser.getBrowserForDocument(topDoc);
   } else {
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -68,19 +68,16 @@ with Files("DirectoryLinksProvider.jsm")
     BUG_COMPONENT = ("Firefox", "New Tab Page")
 
 with Files("E10SUtils.jsm"):
     BUG_COMPONENT = ("Core", "Security: Process Sandboxing")
 
 with Files("ExtensionsUI.jsm"):
     BUG_COMPONENT = ("Toolkit", "WebExtensions: General")
 
-with Files("FullZoomUI.jsm"):
-    BUG_COMPONENT = ("Firefox", "Toolbars and Customization")
-
 with Files("LaterRun.jsm"):
     BUG_COMPONENT = ("Firefox", "Tours")
 
 with Files("PermissionUI.jsm"):
    BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
 
 with Files("PluginContent.jsm"):
     BUG_COMPONENT = ("Core", "Plug-ins")
@@ -113,16 +110,19 @@ with Files("WindowsPreviewPerTab.jsm"):
     BUG_COMPONENT = ("Core", "Widget: Win32")
 
 with Files("offlineAppCache.jsm"):
     BUG_COMPONENT = ("Firefox", "Preferences")
 
 with Files("webrtcUI.jsm"):
     BUG_COMPONENT = ("Firefox", "Device Permissions")
 
+with Files("ZoomUI.jsm"):
+    BUG_COMPONENT = ("Firefox", "Toolbars and Customization")
+
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 XPCSHELL_TESTS_MANIFESTS += [
     'test/unit/social/xpcshell.ini',
     'test/unit/xpcshell.ini',
 ]
 
 EXTRA_JS_MODULES += [
@@ -139,31 +139,31 @@ EXTRA_JS_MODULES += [
     'ContentSearch.jsm',
     'ContentWebRTC.jsm',
     'DirectoryLinksProvider.jsm',
     'E10SUtils.jsm',
     'ExtensionsUI.jsm',
     'Feeds.jsm',
     'FormSubmitObserver.jsm',
     'FormValidationHandler.jsm',
-    'FullZoomUI.jsm',
     'LaterRun.jsm',
     'offlineAppCache.jsm',
     'PermissionUI.jsm',
     'PluginContent.jsm',
     'ProcessHangMonitor.jsm',
     'ReaderParent.jsm',
     'RecentWindow.jsm',
     'RemotePrompt.jsm',
     'Sanitizer.jsm',
     'SitePermissions.jsm',
     'Social.jsm',
     'SocialService.jsm',
     'TransientPrefs.jsm',
     'webrtcUI.jsm',
+    'ZoomUI.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXTRA_JS_MODULES += [
         'Windows8WindowFrameColor.jsm',
         'WindowsJumpLists.jsm',
         'WindowsPreviewPerTab.jsm',
     ]
--- a/browser/themes/shared/controlcenter/panel.inc.css
+++ b/browser/themes/shared/controlcenter/panel.inc.css
@@ -135,32 +135,30 @@
 
 .identity-popup-expander:-moz-locale-dir(rtl) {
   transform: scaleX(-1);
 }
 
 .identity-popup-expander[panel-multiview-anchor] {
   transition: background-color 250ms ease-in;
   background-color: Highlight;
-  background-image: url("chrome://browser/skin/controlcenter/arrow-subview-back.svg"),
-                    linear-gradient(rgba(255,255,255,0.3), transparent);
+  background-image: url("chrome://browser/skin/controlcenter/arrow-subview-back.svg");
 }
 
 .identity-popup-expander > .button-box {
   padding: 0;
 }
 
 .identity-popup-expander:not([panel-multiview-anchor]) > .button-box {
   border-left: 1px solid var(--panel-separator-color);
 }
 
 .identity-popup-expander:hover {
   background-color: var(--arrowpanel-dimmed);
-  background-image: url("chrome://browser/skin/controlcenter/arrow-subview.svg"),
-                    linear-gradient(rgba(255,255,255,0.3), transparent);
+  background-image: url("chrome://browser/skin/controlcenter/arrow-subview.svg");
 }
 
 .identity-popup-expander:hover:active {
   background-color: var(--arrowpanel-dimmed-further);
   box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
 }
 
 /* CONTENT */
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -7,16 +7,22 @@
 
 #mainPrefPane {
   max-width: 800px;
   padding: 0;
   font: message-box;
   font-size: 1.25rem;
 }
 
+description.indent,
+.indent > description {
+  font-size: 1.18rem;
+  color: #737373;
+}
+
 * {
   -moz-user-select: text;
 }
 
 button,
 treecol,
 html|option {
   /* override the * rule */
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -50,24 +50,24 @@
   @media not all and (-moz-os-version: windows-win7) {
     @media not all and (-moz-os-version: windows-win8) {
       @media (-moz-windows-default-theme) {
         :root:not(:-moz-lwtheme) {
           background-color: hsl(0, 0%, 78%);
         }
 
 %ifdef MOZ_PHOTON_THEME
-        @media (-moz-windows-accent-color-applies: 0) {
+        @media (-moz-windows-accent-color-in-titlebar: 0) {
           :root[tabsintitlebar]:not(:-moz-lwtheme) {
             background-color: hsl(235,33%,19%);
             --titlebar-text-color: hsl(240,9%,98%);
           }
         }
 
-        @media (-moz-windows-accent-color-applies) {
+        @media (-moz-windows-accent-color-in-titlebar) {
           :root[tabsintitlebar]:not(:-moz-window-inactive):not(:-moz-lwtheme) {
             background-color: -moz-win-accentcolor;
             --titlebar-text-color: -moz-win-accentcolortext;
           }
         }
 %endif
 
         :root[tabsintitlebar] .tab-label:-moz-window-inactive {
--- a/devtools/client/inspector/grids/grid-inspector.js
+++ b/devtools/client/inspector/grids/grid-inspector.js
@@ -295,16 +295,17 @@ GridInspector.prototype = {
         }
       }
 
       let fallbackColor = GRID_COLORS[i % GRID_COLORS.length];
       let color = this.getInitialGridColor(nodeFront, fallbackColor);
 
       grids.push({
         id: i,
+        actorID: grid.actorID,
         color,
         gridFragments: grid.gridFragments,
         highlighted: nodeFront == this.highlighters.gridHighlighterShown,
         nodeFront,
       });
     }
 
     this.store.dispatch(updateGrids(grids));
@@ -405,18 +406,28 @@ GridInspector.prototype = {
     try {
       newGridFronts = yield this.layoutInspector.getAllGrids(this.walker.rootNode);
     } catch (e) {
       // This call might fail if called asynchrously after the toolbox is finished
       // closing.
       return;
     }
 
-    // Compare the list of DOM nodes which define these grids.
+    // Get the node front(s) from the current grid(s) so we can compare them to them to
+    // node(s) of the new grids.
     const oldNodeFronts = grids.map(grid => grid.nodeFront.actorID);
+
+    // In some cases, the nodes for current grids may have been removed from the DOM in
+    // which case we need to update.
+    if (grids.length && grids.some(grid => !grid.nodeFront.actorID)) {
+      this.updateGridPanel(newGridFronts);
+      return;
+    }
+
+    // Otherwise, continue comparing with the new grids.
     const newNodeFronts = newGridFronts.filter(grid => grid.containerNodeFront)
                                        .map(grid => grid.containerNodeFront.actorID);
     if (grids.length === newGridFronts.length &&
         oldNodeFronts.sort().join(",") == newNodeFronts.sort().join(",")) {
       // Same list of containers, but let's check if the geometry of the current grid has
       // changed, if it hasn't we can safely abort.
       if (!this.highlighters.gridHighlighterShown ||
           (this.highlighters.gridHighlighterShown &&
--- a/devtools/client/inspector/grids/test/browser.ini
+++ b/devtools/client/inspector/grids/test/browser.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 tags = devtools
 subsuite = devtools
 support-files =
+  doc_iframe_reloaded.html
   head.js
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/inspector/test/shared-head.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
   !/devtools/client/framework/test/shared-redux-head.js
@@ -15,16 +16,17 @@ support-files =
 [browser_grids_color-in-rules-grid-toggle.js]
 [browser_grids_display-setting-extend-grid-lines.js]
 [browser_grids_display-setting-show-grid-line-numbers.js]
 [browser_grids_display-setting-show-grid-areas.js]
 [browser_grids_grid-list-color-picker-on-ESC.js]
 [browser_grids_grid-list-color-picker-on-RETURN.js]
 [browser_grids_grid-list-element-rep.js]
 [browser_grids_grid-list-no-grids.js]
+[browser_grids_grid-list-on-iframe-reloaded.js]
 [browser_grids_grid-list-on-mutation-element-added.js]
 [browser_grids_grid-list-on-mutation-element-removed.js]
 [browser_grids_grid-list-toggle-multiple-grids.js]
 [browser_grids_grid-list-toggle-single-grid.js]
 [browser_grids_grid-outline-cannot-show-outline.js]
 [browser_grids_grid-outline-highlight-area.js]
 [browser_grids_grid-outline-highlight-cell.js]
 [browser_grids_grid-outline-selected-grid.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-iframe-reloaded.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the list of grids does refresh when an iframe containing a grid is removed
+// and re-created.
+// See bug 1378306 where this happened with jsfiddle.
+
+const TEST_URI = URL_ROOT + "doc_iframe_reloaded.html";
+
+add_task(function* () {
+  yield addTab(TEST_URI);
+
+  const { inspector, gridInspector, testActor } = yield openLayoutView();
+  const { document: doc } = gridInspector;
+  const { store, highlighters } = inspector;
+  const gridList = doc.querySelector("#grid-list");
+
+  info("Clicking on the first checkbox to highlight the grid");
+  yield enableTheFirstGrid(doc, inspector);
+
+  is(gridList.childNodes.length, 1, "There's one grid in the list");
+  let checkbox = gridList.querySelector("input");
+  ok(checkbox.checked, "The checkbox is checked");
+  ok(highlighters.gridHighlighterShown, "There's a highlighter shown");
+
+  info("Reload the iframe in content and expect the grid list to update");
+  const oldGrid = store.getState().grids[0];
+  const onNewListUnchecked = waitUntilState(store, state =>
+    state.grids.length == 1 &&
+    state.grids[0].actorID !== oldGrid.actorID &&
+    !state.grids[0].highlighted);
+  const onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+  testActor.eval("window.wrappedJSObject.reloadIFrame();");
+  yield onNewListUnchecked;
+  yield onHighlighterHidden;
+
+  is(gridList.childNodes.length, 1, "There's still one grid in the list");
+
+  info("Highlight the first grid again to make sure this still works");
+  yield enableTheFirstGrid(doc, inspector);
+
+  is(gridList.childNodes.length, 1, "There's again one grid in the list");
+  ok(highlighters.gridHighlighterShown, "There's a highlighter shown");
+});
+
+function* enableTheFirstGrid(doc, { highlighters, store }) {
+  const checkbox = doc.querySelector("#grid-list input");
+
+  const onHighlighterShown = highlighters.once("grid-highlighter-shown");
+  const onCheckboxChange = waitUntilState(store, state =>
+    state.grids.length == 1 && state.grids[0].highlighted);
+
+  checkbox.click();
+
+  yield onHighlighterShown;
+  yield onCheckboxChange;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/doc_iframe_reloaded.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<iframe srcdoc="<style>.grid{display:grid;}</style><div class='grid'><span>a</span><span>b</span></div>"></iframe>
+<script>
+"use strict";
+function reloadIFrame() { // eslint-disable-line no-unused-vars
+  const iFrame = document.querySelector("iframe");
+  iFrame.setAttribute("srcdoc", iFrame.getAttribute("srcdoc"));
+}
+</script>
--- a/devtools/client/inspector/markup/utils.js
+++ b/devtools/client/inspector/markup/utils.js
@@ -1,41 +1,14 @@
 /* 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 getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
-
-function* getNames(x) {
-  yield* Object.getOwnPropertyNames(x);
-  yield* Object.getOwnPropertySymbols(x);
-}
-
-// Utility function to get own properties descriptor map.
-function getOwnPropertyDescriptors(...objects) {
-  let descriptors = {};
-  for (let object of objects) {
-    for (let name of getNames(object)) {
-      descriptors[name] = getOwnPropertyDescriptor(object, name);
-    }
-  }
-  return descriptors;
-}
-
-/**
- * Returns a frozen object with that inherits from the given `prototype` and
- * implements all own properties of the given `properties` object.
- */
-function extend(prototype, properties) {
-  return Object.create(prototype,
-                       getOwnPropertyDescriptors(properties));
-}
-
 /**
  * Apply a 'flashed' background and foreground color to elements. Intended
  * to be used with flashElementOff as a way of drawing attention to an element.
  *
  * @param  {Node} backgroundElt
  *         The element to set the highlighted background color on.
  * @param  {Node} foregroundElt
  *         The element to set the matching foreground color on.
@@ -59,17 +32,17 @@ function flashElementOn(backgroundElt, f
   );
 }
 
 /**
  * Remove a 'flashed' background and foreground color to elements.
  * See flashElementOn.
  *
  * @param  {Node} backgroundElt
- *         The element to reomve the highlighted background color on.
+ *         The element to remove the highlighted background color on.
  * @param  {Node} foregroundElt
  *         The element to remove the matching foreground color on.
  *         Optional.  This will equal backgroundElt if not set.
  */
 function flashElementOff(backgroundElt, foregroundElt = backgroundElt) {
   if (!backgroundElt || !foregroundElt) {
     return;
   }
@@ -149,15 +122,14 @@ function truncateString(str, maxLength) 
   }
 
   return str.substring(0, Math.ceil(maxLength / 2)) +
          "…" +
          str.substring(str.length - Math.floor(maxLength / 2));
 }
 
 module.exports = {
-  extend,
   flashElementOn,
   flashElementOff,
   getAutocompleteMaxWidth,
   parseAttributeValues,
   truncateString,
 };
--- a/devtools/client/inspector/markup/views/element-container.js
+++ b/devtools/client/inspector/markup/views/element-container.js
@@ -10,17 +10,17 @@ const promise = require("promise");
 const Services = require("Services");
 const {Task} = require("devtools/shared/task");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const clipboardHelper = require("devtools/shared/platform/clipboard");
 const {setImageTooltip, setBrokenImageTooltip} =
       require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
 const MarkupContainer = require("devtools/client/inspector/markup/views/markup-container");
 const ElementEditor = require("devtools/client/inspector/markup/views/element-editor");
-const {extend} = require("devtools/client/inspector/markup/utils");
+const {extend} = require("devtools/shared/extend");
 
 // Lazy load this module as _buildEventTooltipContent is only called on click
 loader.lazyRequireGetter(this, "setEventTooltip",
   "devtools/client/shared/widgets/tooltip/EventTooltipHelper", true);
 
 /**
  * An implementation of MarkupContainer for Elements that can contain
  * child nodes.
--- a/devtools/client/inspector/markup/views/read-only-container.js
+++ b/devtools/client/inspector/markup/views/read-only-container.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const ReadOnlyEditor = require("devtools/client/inspector/markup/views/read-only-editor");
 const MarkupContainer = require("devtools/client/inspector/markup/views/markup-container");
-const {extend} = require("devtools/client/inspector/markup/utils");
+const {extend} = require("devtools/shared/extend");
 
 /**
  * An implementation of MarkupContainer for Pseudo Elements,
  * Doctype nodes, or any other type generic node that doesn't
  * fit for other editors.
  * Does not allow any editing, just viewing / selecting.
  *
  * @param  {MarkupView} markupView
--- a/devtools/client/inspector/markup/views/text-container.js
+++ b/devtools/client/inspector/markup/views/text-container.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const TextEditor = require("devtools/client/inspector/markup/views/text-editor");
 const MarkupContainer = require("devtools/client/inspector/markup/views/markup-container");
-const {extend} = require("devtools/client/inspector/markup/utils");
+const {extend} = require("devtools/shared/extend");
 
 /**
  * An implementation of MarkupContainer for text node and comment nodes.
  * Allows basic text editing in a textarea.
  *
  * @param  {MarkupView} markupView
  *         The markup view that owns this container.
  * @param  {NodeFront} node
--- a/devtools/client/shared/doorhanger.js
+++ b/devtools/client/shared/doorhanger.js
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Services = require("Services");
 const { DOMHelpers } = require("resource://devtools/client/shared/DOMHelpers.jsm");
 const { Task } = require("devtools/shared/task");
 const defer = require("devtools/shared/defer");
-const { getMostRecentBrowserWindow } = require("sdk/window/utils");
 
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const DEV_EDITION_PROMO_URL = "chrome://devtools/content/framework/dev-edition-promo/dev-edition-promo.xul";
 const DEV_EDITION_PROMO_ENABLED_PREF = "devtools.devedition.promo.enabled";
 const DEV_EDITION_PROMO_SHOWN_PREF = "devtools.devedition.promo.shown";
 const DEV_EDITION_PROMO_URL_PREF = "devtools.devedition.promo.url";
 
 /**
@@ -145,16 +144,16 @@ function onFrameLoad(frame) {
     };
     frame.addEventListener("DOMContentLoaded", callback);
   }
 
   return promise;
 }
 
 function getGBrowser() {
-  return getMostRecentBrowserWindow().gBrowser;
+  return Services.wm.getMostRecentWindow("navigator:browser").gBrowser;
 }
 
 function wait(n) {
   let { resolve, promise } = defer();
   setTimeout(resolve, n);
   return promise;
 }
--- a/devtools/client/webconsole/console-output.js
+++ b/devtools/client/webconsole/console-output.js
@@ -19,25 +19,23 @@ loader.lazyRequireGetter(this, "ObjectCl
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 
 const WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
 const { getSourceNames } = require("devtools/client/shared/source-utils");
 const {Task} = require("devtools/shared/task");
 const l10n = require("devtools/client/webconsole/webconsole-l10n");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const {PluralForm} = require("devtools/shared/plural-form");
+const {extend} = require("devtools/shared/extend");
 
 const MAX_STRING_GRIP_LENGTH = 36;
 const {ELLIPSIS} = require("devtools/shared/l10n");
 
 const validProtocols = /^(http|https|ftp|data|javascript|resource|chrome):/i;
 
-const extend = (prototype, properties) =>
-  Object.create(prototype, Object.getOwnPropertyDescriptors(properties));
-
 // Constants for compatibility with the Web Console output implementation before
 // bug 778766.
 // TODO: remove these once bug 778766 is fixed.
 const COMPAT = {
   // The various categories of messages.
   CATEGORIES: {
     NETWORK: 0,
     CSS: 1,
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -1,18 +1,16 @@
 /* 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 {Cc, Ci, Cu} = require("chrome");
-
 var WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
-var { extend } = require("sdk/core/heritage");
+const {extend} = require("devtools/shared/extend");
 var {TargetFactory} = require("devtools/client/framework/target");
 var {Tools} = require("devtools/client/definitions");
 const { Task } = require("devtools/shared/task");
 var promise = require("promise");
 var Services = require("Services");
 
 loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
 loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole", true);
--- a/devtools/server/actors/reflow.js
+++ b/devtools/server/actors/reflow.js
@@ -23,17 +23,16 @@
  *   listens to reflow events via the docshell,
  *   These dedicated classes are used by the LayoutChangesObserver.
  */
 
 const {Ci} = require("chrome");
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 const protocol = require("devtools/shared/protocol");
 const events = require("sdk/event/core");
-const Heritage = require("sdk/core/heritage");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {reflowSpec} = require("devtools/shared/specs/reflow");
 
 /**
  * The reflow actor tracks reflows and emits events about them.
  */
 exports.ReflowActor = protocol.ActorClassWithSpec(reflowSpec, {
   initialize: function (conn, tabActor) {
@@ -420,85 +419,86 @@ function releaseLayoutChangesObserver(ta
 exports.releaseLayoutChangesObserver = releaseLayoutChangesObserver;
 
 /**
  * Reports any reflow that occurs in the tabActor's docshells.
  * @extends Observable
  * @param {TabActor} tabActor
  * @param {Function} callback Executed everytime a reflow occurs
  */
-function ReflowObserver(tabActor, callback) {
-  Observable.call(this, tabActor, callback);
-}
+class ReflowObserver extends Observable {
+  constructor(tabActor, callback) {
+    super(tabActor, callback);
+  }
 
-ReflowObserver.prototype = Heritage.extend(Observable.prototype, {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
-                                         Ci.nsISupportsWeakReference]),
-
-  _startListeners: function (windows) {
+  _startListeners(windows) {
     for (let window of windows) {
       let docshell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                      .getInterface(Ci.nsIWebNavigation)
                      .QueryInterface(Ci.nsIDocShell);
       docshell.addWeakReflowObserver(this);
     }
-  },
+  }
 
-  _stopListeners: function (windows) {
+  _stopListeners(windows) {
     for (let window of windows) {
       try {
         let docshell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIWebNavigation)
                        .QueryInterface(Ci.nsIDocShell);
         docshell.removeWeakReflowObserver(this);
       } catch (e) {
         // Corner cases where a global has already been freed may happen, in
         // which case, no need to remove the observer.
       }
     }
-  },
+  }
 
-  reflow: function (start, end) {
+  reflow(start, end) {
     this.notifyCallback(start, end, false);
-  },
+  }
 
-  reflowInterruptible: function (start, end) {
+  reflowInterruptible(start, end) {
     this.notifyCallback(start, end, true);
   }
-});
+}
+
+ReflowObserver.prototype.QueryInterface = XPCOMUtils
+  .generateQI([Ci.nsIReflowObserver, Ci.nsISupportsWeakReference]);
 
 /**
  * Reports window resize events on the tabActor's windows.
  * @extends Observable
  * @param {TabActor} tabActor
  * @param {Function} callback Executed everytime a resize occurs
  */
-function WindowResizeObserver(tabActor, callback) {
-  Observable.call(this, tabActor, callback);
-  this.onResize = this.onResize.bind(this);
-}
+class WindowResizeObserver extends Observable {
 
-WindowResizeObserver.prototype = Heritage.extend(Observable.prototype, {
-  _startListeners: function () {
+  constructor(tabActor, callback) {
+    super(tabActor, callback);
+    this.onResize = this.onResize.bind(this);
+  }
+
+  _startListeners() {
     this.listenerTarget.addEventListener("resize", this.onResize);
-  },
+  }
 
-  _stopListeners: function () {
+  _stopListeners() {
     this.listenerTarget.removeEventListener("resize", this.onResize);
-  },
+  }
 
-  onResize: function () {
+  onResize() {
     this.notifyCallback();
-  },
+  }
 
   get listenerTarget() {
     // For the rootActor, return its window.
     if (this.tabActor.isRootActor) {
       return this.tabActor.window;
     }
 
     // Otherwise, get the tabActor's chromeEventHandler.
     return this.tabActor.window.QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIWebNavigation)
                                .QueryInterface(Ci.nsIDocShell)
                                .chromeEventHandler;
   }
-});
+}
new file mode 100644
--- /dev/null
+++ b/devtools/shared/extend.js
@@ -0,0 +1,15 @@
+/* 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";
+
+/**
+ * Utility function, that is useful for creating objects that inherit from other
+ * objects, without associated classes.
+ *
+ * Replacement for `extends` API from "sdk/core/heritage".
+ */
+exports.extend = function (prototype, properties) {
+  return Object.create(prototype, Object.getOwnPropertyDescriptors(properties));
+};
--- a/devtools/shared/gcli/commands/rulers.js
+++ b/devtools/shared/gcli/commands/rulers.js
@@ -1,17 +1,16 @@
 /* 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 events = require("sdk/event/core");
 
-loader.lazyRequireGetter(this, "getOuterId", "sdk/window/utils", true);
 loader.lazyRequireGetter(this, "CommandState",
   "devtools/shared/gcli/command-state", true);
 
 const l10n = require("gcli/l10n");
 require("devtools/server/actors/inspector");
 const { RulersHighlighter, HighlighterEnvironment } =
   require("devtools/server/actors/highlighters");
 
--- a/devtools/shared/moz.build
+++ b/devtools/shared/moz.build
@@ -47,25 +47,26 @@ DevToolsModules(
     'builtin-modules.js',
     'content-observer.js',
     'defer.js',
     'deprecated-sync-thenables.js',
     'DevToolsUtils.js',
     'dom-node-constants.js',
     'dom-node-filter-constants.js',
     'event-emitter.js',
+    'extend.js',
     'flags.js',
     'indentation.js',
     'l10n.js',
     'loader-plugin-raw.jsm',
     'Loader.jsm',
     'Parser.jsm',
     'path.js',
     'plural-form.js',
     'protocol.js',
     'system.js',
     'task.js',
     'ThreadSafeDevToolsUtils.js',
     'wasm-source-map.js',
 )
 
-with Files('**'):
-    BUG_COMPONENT = ('Firefox', 'Developer Tools')
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools')
--- a/devtools/shared/webconsole/server-logger.js
+++ b/devtools/shared/webconsole/server-logger.js
@@ -2,19 +2,17 @@
 /* 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 {Ci} = require("chrome");
-const {Class} = require("sdk/core/heritage");
 const Services = require("Services");
-
 const {DebuggerServer} = require("devtools/server/main");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
 loader.lazyGetter(this, "NetworkHelper", () => require("devtools/shared/webconsole/network-helper"));
 
 // Helper tracer. Should be generic sharable by other modules (bug 1171927)
 const trace = {
   log: function () {
@@ -30,42 +28,38 @@ const acceptableHeaders = ["x-chromelogg
  * within HTTP headers and sending them to the client.
  *
  * The logic is based on "http-on-examine-response" event that is
  * sent when a response from the server is received. Consequently HTTP
  * headers are parsed to find server side logs.
  *
  * A listeners for "http-on-examine-response" is registered when
  * the listener starts and removed when destroy is executed.
+ *
+ * @param {Object} win (nsIDOMWindow):
+ *        filter network requests by the associated window object.
+ *        If null (i.e. in the browser context) log everything
+ * @param {Object} owner
+ *        The {@WebConsoleActor} instance
  */
-var ServerLoggingListener = Class({
-  /**
-   * Initialization of the listener. The main step during the initialization
-   * process is registering a listener for "http-on-examine-response" event.
-   *
-   * @param {Object} win (nsIDOMWindow):
-   *        filter network requests by the associated window object.
-   *        If null (i.e. in the browser context) log everything
-   * @param {Object} owner
-   *        The {@WebConsoleActor} instance
-   */
-  initialize: function (win, owner) {
-    trace.log("ServerLoggingListener.initialize; ", owner.actorID,
-      ", child process: ", DebuggerServer.isInChildProcess);
+function ServerLoggingListener(win, owner) {
+  trace.log("ServerLoggingListener.initialize; ", owner.actorID,
+    ", child process: ", DebuggerServer.isInChildProcess);
+
+  this.owner = owner;
+  this.window = win;
 
-    this.owner = owner;
-    this.window = win;
+  this.onExamineResponse = this.onExamineResponse.bind(this);
+  this.onExamineHeaders = this.onExamineHeaders.bind(this);
+  this.onParentMessage = this.onParentMessage.bind(this);
 
-    this.onExamineResponse = this.onExamineResponse.bind(this);
-    this.onExamineHeaders = this.onExamineHeaders.bind(this);
-    this.onParentMessage = this.onParentMessage.bind(this);
+  this.attach();
+}
 
-    this.attach();
-  },
-
+ServerLoggingListener.prototype = {
   /**
    * The destroy is called by the parent WebConsoleActor actor.
    */
   destroy: function () {
     trace.log("ServerLoggingListener.destroy; ", this.owner.actorID,
       ", child process: ", DebuggerServer.isInChildProcess);
 
     this.detach();
@@ -372,17 +366,17 @@ var ServerLoggingListener = Class({
       }
     }
 
     trace.log("ServerLoggingListener.sendMessage; raw: ",
       msg.logs.join(", "), message);
 
     this.owner.onServerLogCall(message);
   },
-});
+};
 
 // Helpers
 
 /**
  * Parse printf-like specifiers ("%f", "%d", ...) and
  * format the logs according to them.
  */
 function format(msg) {
--- a/devtools/shared/worker/worker.js
+++ b/devtools/shared/worker/worker.js
@@ -134,20 +134,19 @@
    *
    * @param {function} fn
    * @return {function}
    */
   function workerify(fn) {
     console.warn("`workerify` should only be used in tests or measuring performance. " +
                  "This creates an object URL on the browser window, and should not be " +
                  "used in production.");
-    // Fetch via window/utils here as we don't want to include
-    // this module normally.
-    let { getMostRecentBrowserWindow } = require("sdk/window/utils");
-    let { URL, Blob } = getMostRecentBrowserWindow();
+    // Fetch modules here as we don't want to include it normally.
+    const Services = require("Services");
+    let { URL, Blob } = Services.wm.getMostRecentWindow("navigator:browser");
     let stringifiedFn = createWorkerString(fn);
     let blob = new Blob([stringifiedFn]);
     let url = URL.createObjectURL(blob);
     let worker = new DevToolsWorker(url);
 
     let wrapperFn = data => worker.performTask("workerifiedTask", data);
 
     wrapperFn.destroy = function () {
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -103,20 +103,32 @@ PostMessageEvent::Run()
       return NS_OK;
 
     // Note: This is contrary to the spec with respect to file: URLs, which
     //       the spec groups into a single origin, but given we intentionally
     //       don't do that in other places it seems better to hold the line for
     //       now.  Long-term, we want HTML5 to address this so that we can
     //       be compliant while being safer.
     if (!targetPrin->Equals(mProvidedPrincipal)) {
-      MOZ_DIAGNOSTIC_ASSERT(ChromeUtils::IsOriginAttributesEqualIgnoringFPD(mProvidedPrincipal->OriginAttributesRef(),
-                                                                            targetPrin->OriginAttributesRef()),
-                            "Unexpected postMessage call to a window with mismatched "
-                            "origin attributes");
+      OriginAttributes sourceAttrs = mProvidedPrincipal->OriginAttributesRef();
+      OriginAttributes targetAttrs = targetPrin->OriginAttributesRef();
+
+      MOZ_DIAGNOSTIC_ASSERT(sourceAttrs.mAppId == targetAttrs.mAppId,
+        "Target and source should have the same mAppId attribute.");
+      MOZ_DIAGNOSTIC_ASSERT(sourceAttrs.mUserContextId == targetAttrs.mUserContextId,
+        "Target and source should have the same userContextId attribute.");
+      MOZ_DIAGNOSTIC_ASSERT(sourceAttrs.mInIsolatedMozBrowser == targetAttrs.mInIsolatedMozBrowser,
+        "Target and source should have the same inIsolatedMozBrowser attribute.");
+
+      if (!nsContentUtils::IsSystemOrExpandedPrincipal(targetPrin) &&
+          !nsContentUtils::IsSystemOrExpandedPrincipal(mProvidedPrincipal) &&
+          !mTrustedCaller) {
+        MOZ_DIAGNOSTIC_ASSERT(sourceAttrs.mPrivateBrowsingId == targetAttrs.mPrivateBrowsingId,
+          "Target and source should have the same mPrivateBrowsingId attribute.");
+      }
 
       nsAutoString providedOrigin, targetOrigin;
       nsresult rv = nsContentUtils::GetUTFOrigin(targetPrin, targetOrigin);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = nsContentUtils::GetUTFOrigin(mProvidedPrincipal, providedOrigin);
       NS_ENSURE_SUCCESS(rv, rv);
 
       const char16_t* params[] = { providedOrigin.get(), targetOrigin.get() };
--- a/dom/base/nsContentIterator.cpp
+++ b/dom/base/nsContentIterator.cpp
@@ -10,16 +10,17 @@
 #include "nsIContentIterator.h"
 #include "nsRange.h"
 #include "nsIContent.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsContentUtils.h"
 #include "nsINode.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsIParserService.h"
 
 using mozilla::DebugOnly;
 
 // couple of utility static functs
 
 ///////////////////////////////////////////////////////////////////////////
 // NodeToParentOffset: returns the node's parent and offset.
 //
@@ -366,20 +367,27 @@ nsContentIterator::Init(nsIDOMRange* aDO
     // No children (possibly a <br> or text node), or index is after last child.
 
     if (mPre) {
       // XXX: In the future, if start offset is after the last
       //      character in the cdata node, should we set mFirst to
       //      the next sibling?
 
       // Normally we would skip the start node because the start node is outside
-      // of the range in pre mode. However, if startIndx == 0, it means the node
-      // has no children, and the node may be <br> or something. We don't skip
-      // the node in this case in order to address bug 1215798.
-      if (!startIsData && startIndx) {
+      // of the range in pre mode. However, if startIndx == 0, and the node is a
+      // non-container node (e.g. <br>), we don't skip the node in this case in
+      // order to address bug 1215798.
+      bool startIsContainer = true;
+      if (startNode->IsHTMLElement()) {
+        if (nsIParserService* ps = nsContentUtils::GetParserService()) {
+          nsIAtom* name = startNode->NodeInfo()->NameAtom();
+          ps->IsContainer(ps->HTMLAtomTagToId(name), startIsContainer);
+        }
+      }
+      if (!startIsData && (startIsContainer || startIndx)) {
         mFirst = GetNextSibling(startNode);
         NS_WARNING_ASSERTION(mFirst, "GetNextSibling returned null");
 
         // Does mFirst node really intersect the range?  The range could be
         // 'degenerate', i.e., not collapsed but still contain no content.
         if (mFirst &&
             NS_WARN_IF(!NodeIsInTraversalRange(mFirst, mPre, startNode,
                                                startIndx, endNode, endIndx))) {
@@ -422,24 +430,32 @@ nsContentIterator::Init(nsIDOMRange* aDO
   bool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE);
 
   if (endIsData || !endNode->HasChildren() || endIndx == 0) {
     if (mPre) {
       if (NS_WARN_IF(!endNode->IsContent())) {
         // Not much else to do here...
         mLast = nullptr;
       } else {
-        // If the end node is an empty element and the end offset is 0,
+        // If the end node is a non-container element and the end offset is 0,
         // the last element should be the previous node (i.e., shouldn't
         // include the end node in the range).
-        if (!endIsData && !endNode->HasChildren() && !endIndx) {
+        bool endIsContainer = true;
+        if (endNode->IsHTMLElement()) {
+          if (nsIParserService* ps = nsContentUtils::GetParserService()) {
+            nsIAtom* name = endNode->NodeInfo()->NameAtom();
+            ps->IsContainer(ps->HTMLAtomTagToId(name), endIsContainer);
+          }
+        }
+        if (!endIsData && !endIsContainer && !endIndx) {
           mLast = PrevNode(endNode);
           NS_WARNING_ASSERTION(mLast, "PrevNode returned null");
-          if (NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre,
-                                                 startNode, startIndx,
+          if (mLast && mLast != mFirst &&
+              NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre,
+                                                 mFirst, 0,
                                                  endNode, endIndx))) {
             mLast = nullptr;
           }
         } else {
           mLast = endNode->AsContent();
         }
       }
     } else {
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -2237,17 +2237,17 @@ GK_ATOM(forcemessagemanager, "forcemessa
 // Names for system metrics
 GK_ATOM(color_picker_available, "color-picker-available")
 GK_ATOM(scrollbar_start_backward, "scrollbar-start-backward")
 GK_ATOM(scrollbar_start_forward, "scrollbar-start-forward")
 GK_ATOM(scrollbar_end_backward, "scrollbar-end-backward")
 GK_ATOM(scrollbar_end_forward, "scrollbar-end-forward")
 GK_ATOM(scrollbar_thumb_proportional, "scrollbar-thumb-proportional")
 GK_ATOM(overlay_scrollbars, "overlay-scrollbars")
-GK_ATOM(windows_accent_color_applies, "windows-accent-color-applies")
+GK_ATOM(windows_accent_color_in_titlebar, "windows-accent-color-in-titlebar")
 GK_ATOM(windows_default_theme, "windows-default-theme")
 GK_ATOM(mac_graphite_theme, "mac-graphite-theme")
 GK_ATOM(mac_yosemite_theme, "mac-yosemite-theme")
 GK_ATOM(windows_compositor, "windows-compositor")
 GK_ATOM(windows_glass, "windows-glass")
 GK_ATOM(touch_enabled, "touch-enabled")
 GK_ATOM(menubar_drag, "menubar-drag")
 GK_ATOM(swipe_animation_enabled, "swipe-animation-enabled")
@@ -2267,17 +2267,17 @@ GK_ATOM(windows_theme_generic, "windows-
 // And the same again, as media query keywords.
 GK_ATOM(_moz_color_picker_available, "-moz-color-picker-available")
 GK_ATOM(_moz_scrollbar_start_backward, "-moz-scrollbar-start-backward")
 GK_ATOM(_moz_scrollbar_start_forward, "-moz-scrollbar-start-forward")
 GK_ATOM(_moz_scrollbar_end_backward, "-moz-scrollbar-end-backward")
 GK_ATOM(_moz_scrollbar_end_forward, "-moz-scrollbar-end-forward")
 GK_ATOM(_moz_scrollbar_thumb_proportional, "-moz-scrollbar-thumb-proportional")
 GK_ATOM(_moz_overlay_scrollbars, "-moz-overlay-scrollbars")
-GK_ATOM(_moz_windows_accent_color_applies, "-moz-windows-accent-color-applies")
+GK_ATOM(_moz_windows_accent_color_in_titlebar, "-moz-windows-accent-color-in-titlebar")
 GK_ATOM(_moz_windows_default_theme, "-moz-windows-default-theme")
 GK_ATOM(_moz_mac_graphite_theme, "-moz-mac-graphite-theme")
 GK_ATOM(_moz_mac_yosemite_theme, "-moz-mac-yosemite-theme")
 GK_ATOM(_moz_windows_compositor, "-moz-windows-compositor")
 GK_ATOM(_moz_windows_classic, "-moz-windows-classic")
 GK_ATOM(_moz_windows_glass, "-moz-windows-glass")
 GK_ATOM(_moz_windows_theme, "-moz-windows-theme")
 GK_ATOM(_moz_os_version, "-moz-os-version")
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -453,28 +453,30 @@ nsRange::CharacterDataChanged(nsIDocumen
     // then we need to increment the corresponding offset to account for the new
     // text node that will be inserted.  If so, we need to prevent the next
     // ContentInserted or ContentAppended for this range from incrementing it
     // again (when the new text node is notified).
     nsINode* parentNode = aContent->GetParentNode();
     int32_t index = -1;
     if (parentNode == mEndContainer && mEndOffset > 0 &&
         (index = parentNode->IndexOf(aContent)) + 1 == mEndOffset) {
-      ++mEndOffset;
+      newEndNode = mEndContainer;
+      newEndOffset = mEndOffset + 1;
       mEndOffsetWasIncremented = true;
     }
     if (parentNode == mStartContainer && mStartOffset > 0 &&
         (index != -1 ? index : parentNode->IndexOf(aContent)) + 1 == mStartOffset) {
-      ++mStartOffset;
+      newStartNode = mStartContainer;
+      newStartOffset = mStartOffset + 1;
       mStartOffsetWasIncremented = true;
     }
 #ifdef DEBUG
     if (mStartOffsetWasIncremented || mEndOffsetWasIncremented) {
       mAssertNextInsertOrAppendIndex =
-        (mStartOffsetWasIncremented ? mStartOffset : mEndOffset) - 1;
+        (mStartOffsetWasIncremented ? newStartOffset : newEndOffset) - 1;
       mAssertNextInsertOrAppendNode = aInfo->mDetails->mNextSibling;
     }
 #endif
   }
 
   // If the changed node contains our start boundary and the change starts
   // before the boundary we'll need to adjust the offset.
   if (aContent == mStartContainer &&
@@ -499,17 +501,18 @@ nsRange::CharacterDataChanged(nsIDocumen
         RegisterCommonAncestor(newStartNode);
       }
       if (mStartContainer->IsDescendantOfCommonAncestorForRangeInSelection()) {
         newStartNode->SetDescendantOfCommonAncestorForRangeInSelection();
       }
     } else {
       // If boundary is inside changed text, position it before change
       // else adjust start offset for the change in length.
-      mStartOffset = static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd ?
+      newStartNode = mStartContainer;
+      newStartOffset = static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd ?
         aInfo->mChangeStart :
         mStartOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
           aInfo->mReplaceLength;
     }
   }
 
   // Do the same thing for the end boundary, except for splitText of a node
   // with no parent then only switch to the new node if the start boundary
@@ -533,17 +536,18 @@ nsRange::CharacterDataChanged(nsIDocumen
         UnregisterCommonAncestor(mStartContainer);
         RegisterCommonAncestor(mStartContainer->GetParentNode());
         newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
       } else if (mEndContainer->
                    IsDescendantOfCommonAncestorForRangeInSelection()) {
         newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
       }
     } else {
-      mEndOffset = static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd ?
+      newEndNode = mEndContainer;
+      newEndOffset = static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd ?
         aInfo->mChangeStart :
         mEndOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
           aInfo->mReplaceLength;
     }
   }
 
   if (aInfo->mDetails &&
       aInfo->mDetails->mType == CharacterDataChangeInfo::Details::eMerge) {
@@ -635,26 +639,31 @@ nsRange::ContentAppended(nsIDocument* aD
 void
 nsRange::ContentInserted(nsIDocument* aDocument,
                          nsIContent* aContainer,
                          nsIContent* aChild,
                          int32_t aIndexInContainer)
 {
   NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
 
+  bool rangeChanged = false;
+  uint32_t newStartOffset = mStartOffset;
+  uint32_t newEndOffset = mEndOffset;
   nsINode* container = NODE_FROM(aContainer, aDocument);
 
   // Adjust position if a sibling was inserted.
   if (container == mStartContainer && aIndexInContainer < mStartOffset &&
       !mStartOffsetWasIncremented) {
-    ++mStartOffset;
+    ++newStartOffset;
+    rangeChanged = true;
   }
   if (container == mEndContainer && aIndexInContainer < mEndOffset &&
       !mEndOffsetWasIncremented) {
-    ++mEndOffset;
+    ++newEndOffset;
+    rangeChanged = true;
   }
   if (container->IsSelectionDescendant() &&
       !aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
     MarkDescendants(aChild);
     aChild->SetDescendantOfCommonAncestorForRangeInSelection();
   }
 
   if (mStartOffsetWasIncremented || mEndOffsetWasIncremented) {
@@ -662,16 +671,21 @@ nsRange::ContentInserted(nsIDocument* aD
     MOZ_ASSERT(mAssertNextInsertOrAppendNode == aChild);
     MOZ_ASSERT(aChild->IsNodeOfType(nsINode::eDATA_NODE));
     mStartOffsetWasIncremented = mEndOffsetWasIncremented = false;
 #ifdef DEBUG
     mAssertNextInsertOrAppendIndex = -1;
     mAssertNextInsertOrAppendNode = nullptr;
 #endif
   }
+
+  if (rangeChanged) {
+    DoSetRange(mStartContainer, newStartOffset,
+               mEndContainer, newEndOffset, mRoot);
+  }
 }
 
 void
 nsRange::ContentRemoved(nsIDocument* aDocument,
                         nsIContent* aContainer,
                         nsIContent* aChild,
                         int32_t aIndexInContainer,
                         nsIContent* aPreviousSibling)
@@ -680,45 +694,50 @@ nsRange::ContentRemoved(nsIDocument* aDo
   MOZ_ASSERT(!mStartOffsetWasIncremented && !mEndOffsetWasIncremented &&
              mAssertNextInsertOrAppendIndex == -1,
              "splitText failed to notify insert/append?");
 
   nsINode* container = NODE_FROM(aContainer, aDocument);
   bool gravitateStart = false;
   bool gravitateEnd = false;
   bool didCheckStartParentDescendant = false;
+  bool rangeChanged = false;
+  uint32_t newStartOffset = mStartOffset;
+  uint32_t newEndOffset = mEndOffset;
 
   // Adjust position if a sibling was removed...
   if (container == mStartContainer) {
     if (aIndexInContainer < mStartOffset) {
-      --mStartOffset;
+      --newStartOffset;
+      rangeChanged = true;
     }
   } else { // ...or gravitate if an ancestor was removed.
     didCheckStartParentDescendant = true;
     gravitateStart =
       nsContentUtils::ContentIsDescendantOf(mStartContainer, aChild);
   }
 
   // Do same thing for end boundry.
   if (container == mEndContainer) {
     if (aIndexInContainer < mEndOffset) {
-      --mEndOffset;
+      --newEndOffset;
+      rangeChanged = true;
     }
   } else if (didCheckStartParentDescendant &&
              mStartContainer == mEndContainer) {
     gravitateEnd = gravitateStart;
   } else {
     gravitateEnd = nsContentUtils::ContentIsDescendantOf(mEndContainer, aChild);
   }
 
-  if (gravitateStart || gravitateEnd) {
+  if (gravitateStart || gravitateEnd || rangeChanged) {
     DoSetRange(gravitateStart ? container : mStartContainer.get(),
-               gravitateStart ? aIndexInContainer : mStartOffset,
+               gravitateStart ? aIndexInContainer : newStartOffset,
                gravitateEnd ? container : mEndContainer.get(),
-               gravitateEnd ? aIndexInContainer : mEndOffset,
+               gravitateEnd ? aIndexInContainer : newEndOffset,
                mRoot);
   }
   if (container->IsSelectionDescendant() &&
       aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
     aChild->ClearDescendantOfCommonAncestorForRangeInSelection();
     UnmarkDescendants(aChild);
   }
 }
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -14,16 +14,17 @@
 #include "nsCaret.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsCopySupport.h"
 #include "nsFocusManager.h"
 #include "nsFontMetrics.h"
 #include "nsFrameSelection.h"
 #include "nsIContentIterator.h"
+#include "nsIParserService.h"
 #include "nsIPresShell.h"
 #include "nsISelection.h"
 #include "nsIFrame.h"
 #include "nsIObjectFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsQueryObject.h"
 #include "nsRange.h"
@@ -2834,19 +2835,43 @@ ContentEventHandler::GetFlatTextLengthIn
 }
 
 nsresult
 ContentEventHandler::GetStartOffset(nsRange* aRange,
                                     uint32_t* aOffset,
                                     LineBreakType aLineBreakType)
 {
   MOZ_ASSERT(aRange);
+  // To match the "no skip start" hack in nsContentIterator::Init, when range
+  // offset is 0 and the range node is not a container, we have to assume the
+  // range _includes_ the node, which means the start offset should _not_
+  // include the node.
+  //
+  // For example, for this content: <br>abc, and range (<br>, 0)-("abc", 1), the
+  // range includes the linebreak from <br>, so the start offset should _not_
+  // include <br>, and the start offset should be 0.
+  //
+  // However, for this content: <p/>abc, and range (<p>, 0)-("abc", 1), the
+  // range does _not_ include the linebreak from <p> because <p> is a container,
+  // so the start offset _should_ include <p>, and the start offset should be 1.
+
+  nsINode* startNode = aRange->GetStartContainer();
+  bool startIsContainer = true;
+  if (startNode->IsHTMLElement()) {
+    if (nsIParserService* ps = nsContentUtils::GetParserService()) {
+      nsIAtom* name = startNode->NodeInfo()->NameAtom();
+      ps->IsContainer(ps->HTMLAtomTagToId(name), startIsContainer);
+    }
+  }
+  const NodePosition& startPos =
+    startIsContainer
+    ? NodePosition(startNode, aRange->StartOffset())
+    : NodePositionBefore(startNode, aRange->StartOffset());
   return GetFlatTextLengthInRange(
-           NodePosition(mRootContent, 0),
-           NodePosition(aRange->GetStartContainer(), aRange->StartOffset()),
+           NodePosition(mRootContent, 0), startPos,
            mRootContent, aOffset, aLineBreakType);
 }
 
 nsresult
 ContentEventHandler::AdjustCollapsedRangeMaybeIntoTextNode(nsRange* aRange)
 {
   MOZ_ASSERT(aRange);
   MOZ_ASSERT(aRange->Collapsed());
--- a/dom/tests/mochitest/general/frameSelectEvents.html
+++ b/dom/tests/mochitest/general/frameSelectEvents.html
@@ -456,12 +456,30 @@
 
         elt("textarea").setAttribute("style", "");
         await spin();
         is(selectstart, 0, "tdn - ss 2");
         is(selectionchange, 0, "tdn - sc 2");
         is(inputSelectionchange, 0, "tdn - isc 2");
         is(textareaSelectionchange, 0, "tdn - tsc 2");
         reset();
+
+        // When selection is at the end of contentEditable's content,
+        // clearing the content should trigger selection events.
+        var savedContent = elt("ce").innerHTML;
+        document.getSelection().setBaseAndExtent(elt("ce"), 1, elt("ce"), 1);
+        await spin();
+        reset();
+
+        elt("ce").firstChild.remove();
+        await spin();
+        is(selectstart, 0, "clear ce - ss");
+        is(selectionchange, 1, "clear ce - sc");
+        is(inputSelectionchange, 0, "clear ce - isc");
+        is(textareaSelectionchange, 0, "clear ce - tsc");
+
+        elt("ce").innerHTML = savedContent;
+        await spin();
+        reset();
       });
     </script>
   </body>
 </html>
--- a/gfx/layers/LayerMetricsWrapper.h
+++ b/gfx/layers/LayerMetricsWrapper.h
@@ -169,29 +169,16 @@ public:
     return mLayer != nullptr;
   }
 
   explicit operator bool() const
   {
     return IsValid();
   }
 
-  bool IsScrollInfoLayer() const
-  {
-    MOZ_ASSERT(IsValid());
-
-    // If we are not at the bottommost layer then it's
-    // a stack of container layers all the way down to
-    // mLayer, which we can ignore. We only care about
-    // non-container descendants.
-    return Metrics().IsScrollable()
-        && mLayer->AsContainerLayer()
-        && !mLayer->GetFirstChild();
-  }
-
   LayerMetricsWrapper GetParent() const
   {
     MOZ_ASSERT(IsValid());
 
     if (!AtTopLayer()) {
       return LayerMetricsWrapper(mLayer, mIndex + 1);
     }
     if (mLayer->GetParent()) {
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -662,17 +662,17 @@ Layer::HasScrollableFrameMetrics() const
     if (GetFrameMetrics(i).IsScrollable()) {
       return true;
     }
   }
   return false;
 }
 
 bool
-Layer::IsScrollInfoLayer() const
+Layer::IsScrollableWithoutContent() const
 {
   // A scrollable container layer with no children
   return AsContainerLayer()
       && HasScrollableFrameMetrics()
       && !GetFirstChild();
 }
 
 Matrix4x4
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1357,17 +1357,17 @@ public:
   Maybe<ParentLayerIntRect> GetScrolledClipRect() const;
   uint32_t GetContentFlags() { return mSimpleAttrs.ContentFlags(); }
   const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; }
   const ScrollMetadata& GetScrollMetadata(uint32_t aIndex) const;
   const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const;
   uint32_t GetScrollMetadataCount() const { return mScrollMetadata.Length(); }
   const nsTArray<ScrollMetadata>& GetAllScrollMetadata() { return mScrollMetadata; }
   bool HasScrollableFrameMetrics() const;
-  bool IsScrollInfoLayer() const;
+  bool IsScrollableWithoutContent() const;
   const EventRegions& GetEventRegions() const { return mEventRegions; }
   ContainerLayer* GetParent() { return mParent; }
   Layer* GetNextSibling() {
     if (mNextSibling) {
       mNextSibling->CheckCanary();
     }
     return mNextSibling;
   }
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -578,17 +578,17 @@ ComputeClipRegion(GeckoContentController
 template<class ScrollNode> void
 APZCTreeManager::PrintAPZCInfo(const ScrollNode& aLayer,
                                const AsyncPanZoomController* apzc)
 {
   const FrameMetrics& metrics = aLayer.Metrics();
   mApzcTreeLog << "APZC " << apzc->GetGuid()
                << "\tcb=" << metrics.GetCompositionBounds()
                << "\tsr=" << metrics.GetScrollableRect()
-               << (aLayer.IsScrollInfoLayer() ? "\tscrollinfo" : "")
+               << (metrics.IsScrollInfoLayer() ? "\tscrollinfo" : "")
                << (apzc->HasScrollgrab() ? "\tscrollgrab" : "") << "\t"
                << aLayer.Metadata().GetContentDescription().get();
 }
 
 void
 APZCTreeManager::AttachNodeToTree(HitTestingTreeNode* aNode,
                                   HitTestingTreeNode* aParent,
                                   HitTestingTreeNode* aNextSibling)
@@ -602,17 +602,17 @@ APZCTreeManager::AttachNodeToTree(HitTes
     mRootNode = aNode;
     aNode->MakeRoot();
   }
 }
 
 template<class ScrollNode> static EventRegions
 GetEventRegions(const ScrollNode& aLayer)
 {
-  if (aLayer.IsScrollInfoLayer()) {
+  if (aLayer.Metrics().IsScrollInfoLayer()) {
     ParentLayerIntRect compositionBounds(RoundedToInt(aLayer.Metrics().GetCompositionBounds()));
     nsIntRegion hitRegion(compositionBounds.ToUnknownRect());
     EventRegions eventRegions(hitRegion);
     eventRegions.mDispatchToContentHitRegion = eventRegions.mHitRegion;
     return eventRegions;
   }
   return aLayer.GetEventRegions();
 }
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -919,17 +919,17 @@ AsyncCompositionManager::ApplyAsyncConte
           AsyncTransform asyncTransformWithoutOverscroll =
               controller->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing);
           AsyncTransformComponentMatrix overscrollTransform =
               controller->GetOverscrollTransform(AsyncPanZoomController::eForCompositing);
           AsyncTransformComponentMatrix asyncTransform =
               AsyncTransformComponentMatrix(asyncTransformWithoutOverscroll)
             * overscrollTransform;
 
-          if (!layer->IsScrollInfoLayer()) {
+          if (!layer->IsScrollableWithoutContent()) {
             controller->MarkAsyncTransformAppliedToContent();
           }
 
           const ScrollMetadata& scrollMetadata = layer->GetScrollMetadata(i);
           const FrameMetrics& metrics = scrollMetadata.GetMetrics();
 
 #if defined(MOZ_WIDGET_ANDROID)
           // If we find a metrics which is the root content doc, use that. If not, use
@@ -1095,17 +1095,17 @@ LayerIsScrollbarTarget(const LayerMetric
   AsyncPanZoomController* apzc = aTarget.GetApzc();
   if (!apzc) {
     return false;
   }
   const FrameMetrics& metrics = aTarget.Metrics();
   if (metrics.GetScrollId() != aScrollbar->GetScrollbarTargetContainerId()) {
     return false;
   }
-  return !aTarget.IsScrollInfoLayer();
+  return !metrics.IsScrollInfoLayer();
 }
 
 static void
 ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
                                          const LayerMetricsWrapper& aContent,
                                          bool aScrollbarIsDescendant)
 {
   AsyncTransformComponentMatrix clipTransform;
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -621,17 +621,17 @@ ContainerRender(ContainerT* aContainer,
                  RenderTargetIntRect::FromUnknownRect(aClipRect),
                  aGeometry);
   }
 
   // If it is a scrollable container layer with no child layers, and one of the APZCs
   // attached to it has a nonempty async transform, then that transform is not applied
   // to any visible content. Display a warning box (conditioned on the FPS display being
   // enabled).
-  if (gfxPrefs::LayersDrawFPS() && aContainer->IsScrollInfoLayer()) {
+  if (gfxPrefs::LayersDrawFPS() && aContainer->IsScrollableWithoutContent()) {
     // Since aContainer doesn't have any children we can just iterate from the top metrics
     // on it down to the bottom using GetFirstChild and not worry about walking onto another
     // underlying layer.
     for (LayerMetricsWrapper i(aContainer); i; i = i.GetFirstChild()) {
       if (AsyncPanZoomController* apzc = i.GetApzc()) {
         if (!apzc->GetAsyncTransformAppliedToContent()
             && !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForHitTesting)).IsIdentity()) {
           aManager->UnusedApzTransformWarning();
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -32,17 +32,16 @@ WebRenderLayerScrollData::Initialize(Web
   MOZ_ASSERT(mDescendantCount == -1); // Don't allow re-setting an already set value
   mDescendantCount = aDescendantCount;
 
   MOZ_ASSERT(aLayer);
   for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
     mScrollIds.AppendElement(aOwner.AddMetadata(aLayer->GetScrollMetadata(i)));
   }
 
-  mIsScrollInfoLayer = aLayer->AsContainerLayer() && !aLayer->GetFirstChild();
   mTransform = aLayer->GetTransform();
   mTransformIsPerspective = aLayer->GetTransformIsPerspective();
   mEventRegions = aLayer->GetEventRegions();
   mVisibleRegion = aLayer->GetVisibleRegion();
   mReferentId = aLayer->AsRefLayer()
       ? Some(aLayer->AsRefLayer()->GetReferentId())
       : Nothing();
   mEventRegionsOverride = aLayer->AsContainerLayer()
--- a/gfx/layers/wr/WebRenderScrollData.h
+++ b/gfx/layers/wr/WebRenderScrollData.h
@@ -47,17 +47,16 @@ public:
 
   // Return the ScrollMetadata object that used to be on the original Layer
   // at the given index. Since we deduplicate the ScrollMetadata objects into
   // the array in the owning WebRenderScrollData object, we need to be passed
   // in a reference to that owner as well.
   const ScrollMetadata& GetScrollMetadata(const WebRenderScrollData& aOwner,
                                           size_t aIndex) const;
 
-  bool IsScrollInfoLayer() const { return mIsScrollInfoLayer; }
   gfx::Matrix4x4 GetTransform() const { return mTransform; }
   CSSTransformMatrix GetTransformTyped() const;
   bool GetTransformIsPerspective() const { return mTransformIsPerspective; }
   EventRegions GetEventRegions() const { return mEventRegions; }
   const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; }
   Maybe<uint64_t> GetReferentId() const { return mReferentId; }
   EventRegionsOverride GetEventRegionsOverride() const { return mEventRegionsOverride; }
   const ScrollThumbData& GetScrollThumbData() const { return mScrollThumbData; }
@@ -79,17 +78,16 @@ private:
   // mScrollMetadatas array. This indirection is used to deduplicate the
   // ScrollMetadata objects, since there is usually heavy duplication of them
   // within a layer tree.
   nsTArray<size_t> mScrollIds;
 
   // Various data that we collect from the Layer in Initialize(), serialize
   // over IPC, and use on the parent side in APZ.
 
-  bool mIsScrollInfoLayer;
   gfx::Matrix4x4 mTransform;
   bool mTransformIsPerspective;
   EventRegions mEventRegions;
   LayerIntRegion mVisibleRegion;
   Maybe<uint64_t> mReferentId;
   EventRegionsOverride mEventRegionsOverride;
   ScrollThumbData mScrollThumbData;
   uint64_t mScrollbarAnimationId;
@@ -183,17 +181,16 @@ struct ParamTraits<mozilla::layers::WebR
 {
   typedef mozilla::layers::WebRenderLayerScrollData paramType;
 
   static void
   Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mDescendantCount);
     WriteParam(aMsg, aParam.mScrollIds);
-    WriteParam(aMsg, aParam.mIsScrollInfoLayer);
     WriteParam(aMsg, aParam.mTransform);
     WriteParam(aMsg, aParam.mTransformIsPerspective);
     WriteParam(aMsg, aParam.mEventRegions);
     WriteParam(aMsg, aParam.mVisibleRegion);
     WriteParam(aMsg, aParam.mReferentId);
     WriteParam(aMsg, aParam.mEventRegionsOverride);
     WriteParam(aMsg, aParam.mScrollThumbData);
     WriteParam(aMsg, aParam.mScrollbarAnimationId);
@@ -202,17 +199,16 @@ struct ParamTraits<mozilla::layers::WebR
     WriteParam(aMsg, aParam.mFixedPosScrollContainerId);
   }
 
   static bool
   Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mDescendantCount)
         && ReadParam(aMsg, aIter, &aResult->mScrollIds)
-        && ReadParam(aMsg, aIter, &aResult->mIsScrollInfoLayer)
         && ReadParam(aMsg, aIter, &aResult->mTransform)
         && ReadParam(aMsg, aIter, &aResult->mTransformIsPerspective)
         && ReadParam(aMsg, aIter, &aResult->mEventRegions)
         && ReadParam(aMsg, aIter, &aResult->mVisibleRegion)
         && ReadParam(aMsg, aIter, &aResult->mReferentId)
         && ReadParam(aMsg, aIter, &aResult->mEventRegionsOverride)
         && ReadParam(aMsg, aIter, &aResult->mScrollThumbData)
         && ReadParam(aMsg, aIter, &aResult->mScrollbarAnimationId)
--- a/gfx/layers/wr/WebRenderScrollDataWrapper.h
+++ b/gfx/layers/wr/WebRenderScrollDataWrapper.h
@@ -120,24 +120,16 @@ public:
     return mLayer != nullptr;
   }
 
   explicit operator bool() const
   {
     return IsValid();
   }
 
-  bool IsScrollInfoLayer() const
-  {
-    MOZ_ASSERT(IsValid());
-
-    return Metrics().IsScrollable()
-        && mLayer->IsScrollInfoLayer();
-  }
-
   WebRenderScrollDataWrapper GetLastChild() const
   {
     MOZ_ASSERT(IsValid());
 
     if (!AtBottomLayer()) {
       // If we're still walking around in the virtual container layers created
       // by the ScrollMetadata array, we just need to update the metadata index
       // and that's it.
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -330,32 +330,32 @@ TextOverflow::TextOverflow(nsDisplayList
   } else {
     mIStart.Init(style->mTextOverflow.GetRight(direction));
     mIEnd.Init(style->mTextOverflow.GetLeft(direction));
   }
   // The left/right marker string is setup in ExamineLineFrames when a line
   // has overflow on that side.
 }
 
-/* static */ TextOverflow*
+/* static */ UniquePtr<TextOverflow>
 TextOverflow::WillProcessLines(nsDisplayListBuilder*   aBuilder,
                                nsIFrame*               aBlockFrame)
 {
   // Ignore 'text-overflow' for event and frame visibility processing.
   if (aBuilder->IsForEventDelivery() ||
       aBuilder->IsForFrameVisibility() ||
       !CanHaveTextOverflow(aBlockFrame)) {
     return nullptr;
   }
   nsIScrollableFrame* scrollableFrame = nsLayoutUtils::GetScrollableFrameFor(aBlockFrame);
   if (scrollableFrame && scrollableFrame->IsTransformingByAPZ()) {
     // If the APZ is actively scrolling this, don't bother with markers.
     return nullptr;
   }
-  return new TextOverflow(aBuilder, aBlockFrame);
+  return MakeUnique<TextOverflow>(aBuilder, aBlockFrame);
 }
 
 void
 TextOverflow::ExamineFrameSubtree(nsIFrame*       aFrame,
                                   const LogicalRect& aContentArea,
                                   const LogicalRect& aInsideMarkersArea,
                                   FrameHashtable* aFramesToHide,
                                   AlignmentEdges* aAlignmentEdges,
--- a/layout/generic/TextOverflow.h
+++ b/layout/generic/TextOverflow.h
@@ -4,40 +4,52 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TextOverflow_h_
 #define TextOverflow_h_
 
 #include "nsDisplayList.h"
 #include "nsTHashtable.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/WritingModes.h"
 #include <algorithm>
 
 class nsIScrollableFrame;
 class nsLineBox;
 
 namespace mozilla {
 namespace css {
 
 /**
  * A class for rendering CSS3 text-overflow.
  * Usage:
  *  1. allocate an object using WillProcessLines
  *  2. then call ProcessLine for each line you are building display lists for
  */
-class TextOverflow {
+class MOZ_HEAP_CLASS TextOverflow final {
  public:
   /**
    * Allocate an object for text-overflow processing.
    * @return nullptr if no processing is necessary.  The caller owns the object.
    */
-  static TextOverflow* WillProcessLines(nsDisplayListBuilder*   aBuilder,
-                                        nsIFrame*               aBlockFrame);
+  static UniquePtr<TextOverflow>
+  WillProcessLines(nsDisplayListBuilder* aBuilder,
+                   nsIFrame*             aBlockFrame);
+
+  /**
+   * Constructor, which client code SHOULD NOT use directly. Instead, clients
+   * should call WillProcessLines(), which is basically the factory function
+   * for TextOverflow instances.
+   */
+  TextOverflow(nsDisplayListBuilder* aBuilder,
+               nsIFrame* aBlockFrame);
+
   /**
    * Analyze the display lists for text overflow and what kind of item is at
    * the content edges.  Add display items for text-overflow markers as needed
    * and remove or clip items that would overlap a marker.
    */
   void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine);
 
   /**
@@ -50,22 +62,19 @@ class TextOverflow {
    * @return true if aBlockFrmae has text-overflow:clip on both sides.
    */
   static bool HasClippedOverflow(nsIFrame* aBlockFrame);
   /**
    * @return true if aBlockFrame needs analysis for text overflow.
    */
   static bool CanHaveTextOverflow(nsIFrame* aBlockFrame);
 
-  typedef nsTHashtable<nsPtrHashKey<nsIFrame> > FrameHashtable;
+  typedef nsTHashtable<nsPtrHashKey<nsIFrame>> FrameHashtable;
 
- protected:
-  TextOverflow(nsDisplayListBuilder* aBuilder,
-               nsIFrame* aBlockFrame);
-
+ private:
   typedef mozilla::WritingMode WritingMode;
   typedef mozilla::LogicalRect LogicalRect;
 
   struct AlignmentEdges {
     AlignmentEdges() : mAssigned(false) {}
     void Accumulate(WritingMode aWM, const LogicalRect& aRect)
     {
       if (MOZ_LIKELY(mAssigned)) {
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -6751,18 +6751,18 @@ nsBlockFrame::BuildDisplayList(nsDisplay
       if (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT)
          BuildDisplayListForChild(aBuilder, f, aDirtyRect, aLists);
     }
   }
 
   aBuilder->MarkFramesForDisplayList(this, mFloats, aDirtyRect);
 
   // Prepare for text-overflow processing.
-  UniquePtr<TextOverflow> textOverflow(
-    TextOverflow::WillProcessLines(aBuilder, this));
+  UniquePtr<TextOverflow> textOverflow =
+    TextOverflow::WillProcessLines(aBuilder, this);
 
   // We'll collect our lines' display items here, & then append this to aLists.
   nsDisplayListCollection linesDisplayListCollection;
 
   // Don't use the line cursor if we might have a descendant placeholder ...
   // it might skip lines that contain placeholders but don't themselves
   // intersect with the dirty area.
   // In particular, we really want to check ShouldDescendIntoFrame()
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1381682.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<style>
+.foo :not(.bar) + baz {
+  color: red;
+}
+
+.descendant::before {
+  content: "";
+}
+</style>
+<div class="foo">
+  <div class="descendant">
+  </div>
+</div>
+<script>
+  document.body.offsetTop;
+  document.querySelector('.foo').classList.remove('foo');
+</script>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -177,8 +177,9 @@ load content-only-on-link-before.html
 load content-only-on-visited-before.html
 load 1375812-1.html
 load 1377053-1.html
 load 1377256-1.html
 load 1378064-1.html
 load 1378814.html
 load 1380800.html
 load link-transition-before.html
+load 1381682.html
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -1127,19 +1127,19 @@ nsCSSRuleProcessor::InitSystemMetrics()
     sSystemMetrics->AppendElement(nsGkAtoms::mac_graphite_theme);
   }
 
   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacYosemiteTheme, &metricResult);
   if (NS_SUCCEEDED(rv) && metricResult) {
     sSystemMetrics->AppendElement(nsGkAtoms::mac_yosemite_theme);
   }
 
-  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsAccentColorApplies, &metricResult);
+  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsAccentColorInTitlebar, &metricResult);
   if (NS_SUCCEEDED(rv) && metricResult) {
-    sSystemMetrics->AppendElement(nsGkAtoms::windows_accent_color_applies);
+    sSystemMetrics->AppendElement(nsGkAtoms::windows_accent_color_in_titlebar);
   }
 
   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_DWMCompositor, &metricResult);
   if (NS_SUCCEEDED(rv) && metricResult) {
     sSystemMetrics->AppendElement(nsGkAtoms::windows_compositor);
   }
 
   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsGlass, &metricResult);
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -689,21 +689,21 @@ nsMediaFeatures::features[] = {
     &nsGkAtoms::_moz_mac_yosemite_theme,
     nsMediaFeature::eMinMaxNotAllowed,
     nsMediaFeature::eBoolInteger,
     nsMediaFeature::eNoRequirements,
     { &nsGkAtoms::mac_yosemite_theme },
     GetSystemMetric
   },
   {
-    &nsGkAtoms::_moz_windows_accent_color_applies,
+    &nsGkAtoms::_moz_windows_accent_color_in_titlebar,
     nsMediaFeature::eMinMaxNotAllowed,
     nsMediaFeature::eBoolInteger,
     nsMediaFeature::eNoRequirements,
-    { &nsGkAtoms::windows_accent_color_applies },
+    { &nsGkAtoms::windows_accent_color_in_titlebar },
     GetSystemMetric
   },
   {
     &nsGkAtoms::_moz_windows_compositor,
     nsMediaFeature::eMinMaxNotAllowed,
     nsMediaFeature::eBoolInteger,
     nsMediaFeature::eNoRequirements,
     { &nsGkAtoms::windows_compositor },
--- a/layout/style/test/test_media_queries.html
+++ b/layout/style/test/test_media_queries.html
@@ -623,81 +623,81 @@ function run() {
   expression_should_be_parseable("-moz-scrollbar-start-forward");
   expression_should_be_parseable("-moz-scrollbar-end-backward");
   expression_should_be_parseable("-moz-scrollbar-end-forward");
   expression_should_be_parseable("-moz-scrollbar-thumb-proportional");
   expression_should_be_parseable("-moz-overlay-scrollbars");
   expression_should_be_parseable("-moz-windows-default-theme");
   expression_should_be_parseable("-moz-mac-graphite-theme");
   expression_should_be_parseable("-moz-mac-yosemite-theme");
-  expression_should_be_parseable("-moz-windows-accent-color-applies");
+  expression_should_be_parseable("-moz-windows-accent-color-in-titlebar");
   expression_should_be_parseable("-moz-windows-compositor");
   expression_should_be_parseable("-moz-windows-classic");
   expression_should_be_parseable("-moz-windows-glass");
   expression_should_be_parseable("-moz-touch-enabled");
   expression_should_be_parseable("-moz-swipe-animation-enabled");
 
   expression_should_be_parseable("-moz-scrollbar-start-backward: 0");
   expression_should_be_parseable("-moz-scrollbar-start-forward: 0");
   expression_should_be_parseable("-moz-scrollbar-end-backward: 0");
   expression_should_be_parseable("-moz-scrollbar-end-forward: 0");
   expression_should_be_parseable("-moz-scrollbar-thumb-proportional: 0");
   expression_should_be_parseable("-moz-overlay-scrollbars: 0");
   expression_should_be_parseable("-moz-windows-default-theme: 0");
   expression_should_be_parseable("-moz-mac-graphite-theme: 0");
   expression_should_be_parseable("-moz-mac-yosemite-theme: 0");
-  expression_should_be_parseable("-moz-windows-accent-color-applies: 0");
+  expression_should_be_parseable("-moz-windows-accent-color-in-titlebar: 0");
   expression_should_be_parseable("-moz-windows-compositor: 0");
   expression_should_be_parseable("-moz-windows-classic: 0");
   expression_should_be_parseable("-moz-windows-glass: 0");
   expression_should_be_parseable("-moz-touch-enabled: 0");
   expression_should_be_parseable("-moz-swipe-animation-enabled: 0");
 
   expression_should_be_parseable("-moz-scrollbar-start-backward: 1");
   expression_should_be_parseable("-moz-scrollbar-start-forward: 1");
   expression_should_be_parseable("-moz-scrollbar-end-backward: 1");
   expression_should_be_parseable("-moz-scrollbar-end-forward: 1");
   expression_should_be_parseable("-moz-scrollbar-thumb-proportional: 1");
   expression_should_be_parseable("-moz-overlay-scrollbars: 1");
   expression_should_be_parseable("-moz-windows-default-theme: 1");
   expression_should_be_parseable("-moz-mac-graphite-theme: 1");
   expression_should_be_parseable("-moz-mac-yosemite-theme: 1");
-  expression_should_be_parseable("-moz-windows-accent-color-applies: 1");
+  expression_should_be_parseable("-moz-windows-accent-color-in-titlebar: 1");
   expression_should_be_parseable("-moz-windows-compositor: 1");
   expression_should_be_parseable("-moz-windows-classic: 1");
   expression_should_be_parseable("-moz-windows-glass: 1");
   expression_should_be_parseable("-moz-touch-enabled: 1");
   expression_should_be_parseable("-moz-swipe-animation-enabled: 1");
 
   expression_should_not_be_parseable("-moz-scrollbar-start-backward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-start-forward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-end-backward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-end-forward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-thumb-proportional: -1");
   expression_should_not_be_parseable("-moz-overlay-scrollbars: -1");
   expression_should_not_be_parseable("-moz-windows-default-theme: -1");
   expression_should_not_be_parseable("-moz-mac-graphite-theme: -1");
   expression_should_not_be_parseable("-moz-mac-yosemite-theme: -1");
-  expression_should_not_be_parseable("-moz-windows-accent-color-applies: -1");
+  expression_should_not_be_parseable("-moz-windows-accent-color-in-titlebar: -1");
   expression_should_not_be_parseable("-moz-windows-compositor: -1");
   expression_should_not_be_parseable("-moz-windows-classic: -1");
   expression_should_not_be_parseable("-moz-windows-glass: -1");
   expression_should_not_be_parseable("-moz-touch-enabled: -1");
   expression_should_not_be_parseable("-moz-swipe-animation-enabled: -1");
 
   expression_should_not_be_parseable("-moz-scrollbar-start-backward: true");
   expression_should_not_be_parseable("-moz-scrollbar-start-forward: true");
   expression_should_not_be_parseable("-moz-scrollbar-end-backward: true");
   expression_should_not_be_parseable("-moz-scrollbar-end-forward: true");
   expression_should_not_be_parseable("-moz-scrollbar-thumb-proportional: true");
   expression_should_not_be_parseable("-moz-overlay-scrollbars: true");
   expression_should_not_be_parseable("-moz-windows-default-theme: true");
   expression_should_not_be_parseable("-moz-mac-graphite-theme: true");
   expression_should_not_be_parseable("-moz-mac-yosemite-theme: true");
-  expression_should_not_be_parseable("-moz-windows-accent-color-applies: true");
+  expression_should_not_be_parseable("-moz-windows-accent-color-in-titlebar: true");
   expression_should_not_be_parseable("-moz-windows-compositor: true");
   expression_should_not_be_parseable("-moz-windows-classic: true");
   expression_should_not_be_parseable("-moz-windows-glass: true");
   expression_should_not_be_parseable("-moz-touch-enabled: true");
   expression_should_not_be_parseable("-moz-swipe-animation-enabled: true");
 
   // windows theme media queries
   expression_should_be_parseable("-moz-windows-theme: aero");
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipelineFilter.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipelineFilter.cpp
@@ -30,24 +30,24 @@ bool MediaPipelineFilter::Filter(const w
       return true;
     }
     // Some other stream; it is possible that an SSRC has moved, so make sure
     // we don't have that SSRC in our filter any more.
     remote_ssrc_set_.erase(header.ssrc);
     return false;
   }
 
-  if (header.extension.hasRID &&
+  if (!header.extension.rtpStreamId.empty() &&
       remote_rid_set_.size() &&
-      remote_rid_set_.count(header.extension.rid.get())) {
+      remote_rid_set_.count(header.extension.rtpStreamId.data())) {
     return true;
   }
-  if (header.extension.hasRID) {
+  if (!header.extension.rtpStreamId.empty()) {
     MOZ_MTLOG(ML_DEBUG, "MediaPipelineFilter ignoring seq# " << header.sequenceNumber <<
-              " ssrc: " << header.ssrc << " RID: " << header.extension.rid.get());
+              " ssrc: " << header.ssrc << " RID: " << header.extension.rtpStreamId.data());
   }
 
   if (remote_ssrc_set_.count(header.ssrc)) {
     return true;
   }
 
   // Last ditch effort...
   if (payload_type_set_.count(header.payloadType)) {
--- a/media/webrtc/trunk/gtest/moz.build
+++ b/media/webrtc/trunk/gtest/moz.build
@@ -363,16 +363,17 @@ if CONFIG['OS_TARGET'] in ['Darwin', 'Li
         '../webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc',
+        '../webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_payload_registry_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/time_util_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/ulpfec_generator_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator_unittest.cc',
         '../webrtc/modules/utility/source/process_thread_impl_unittest.cc',
         '../webrtc/modules/video_capture/test/video_capture_unittest.cc',
         '../webrtc/modules/video_coding/codecs/test/packet_manipulator.cc',
         '../webrtc/modules/video_coding/codecs/test/predictive_packet_manipulator.cc',
--- a/media/webrtc/trunk/webrtc/common_types.cc
+++ b/media/webrtc/trunk/webrtc/common_types.cc
@@ -15,30 +15,47 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/stringutils.h"
 
 namespace webrtc {
 
 StreamDataCounters::StreamDataCounters() : first_packet_time_ms(-1) {}
 
+constexpr size_t StreamId::kMaxSize;
+
+bool StreamId::IsLegalName(rtc::ArrayView<const char> name) {
+  return (name.size() <= kMaxSize && name.size() > 0 &&
+          std::all_of(name.data(), name.data() + name.size(), isalnum));
+}
+
+void StreamId::Set(const char* data, size_t size) {
+  // If |data| contains \0, the stream id size might become less than |size|.
+  RTC_CHECK_LE(size, kMaxSize);
+  memcpy(value_, data, size);
+  // mozilla: value_ is kMaxSize+1 so we always have room to null terminate
+  value_[size] = 0;
+}
+
+// StreamId is used as member of RTPHeader that is sometimes copied with memcpy
+// and thus assume trivial destructibility.
+static_assert(std::is_trivially_destructible<StreamId>::value, "");
+
 RTPHeaderExtension::RTPHeaderExtension()
     : hasTransmissionTimeOffset(false),
       transmissionTimeOffset(0),
       hasAbsoluteSendTime(false),
       absoluteSendTime(0),
       hasTransportSequenceNumber(false),
       transportSequenceNumber(0),
       hasAudioLevel(false),
       voiceActivity(false),
       audioLevel(0),
       hasVideoRotation(false),
-      videoRotation(kVideoRotation_0),
-      hasRID(false),
-      rid(nullptr) {
+      videoRotation(kVideoRotation_0) {
 }
 
 RTPHeaderExtension::RTPHeaderExtension(const RTPHeaderExtension& rhs) {
   *this = rhs;
 }
 
 RTPHeaderExtension&
 RTPHeaderExtension::operator=(const RTPHeaderExtension& rhs) {
@@ -51,21 +68,18 @@ RTPHeaderExtension::operator=(const RTPH
 
   hasAudioLevel = rhs.hasAudioLevel;
   voiceActivity = rhs.voiceActivity;
   audioLevel = rhs.audioLevel;
 
   hasVideoRotation = rhs.hasVideoRotation;
   videoRotation = rhs.videoRotation;
 
-  hasRID = rhs.hasRID;
- if (rhs.rid) {
-    rid.reset(new char[strlen(rhs.rid.get())+1]);
-    strcpy(rid.get(), rhs.rid.get());
-  }
+  rtpStreamId = rhs.rtpStreamId;
+
   return *this;
 }
 
 RTPHeader::RTPHeader()
     : markerBit(false),
       payloadType(0),
       sequenceNumber(0),
       timestamp(0),
--- a/media/webrtc/trunk/webrtc/common_types.h
+++ b/media/webrtc/trunk/webrtc/common_types.h
@@ -814,16 +814,56 @@ struct PacketTime {
 //
 // Note: Given that this gets embedded in a union, it is up-to the owner to
 // initialize these values.
 struct PlayoutDelay {
   int min_ms;
   int max_ms;
 };
 
+// Class to represent RtpStreamId which is a string.
+// Unlike std::string, it can be copied with memcpy and cleared with memset.
+// Empty value represent unset RtpStreamId.
+class StreamId {
+ public:
+  // Stream id is limited to 16 bytes because it is the maximum length
+  // that can be encoded with one-byte header extensions.
+  static constexpr size_t kMaxSize = 16;
+
+  static bool IsLegalName(rtc::ArrayView<const char> name);
+
+  StreamId() { value_[0] = 0; }
+  explicit StreamId(rtc::ArrayView<const char> value) {
+    Set(value.data(), value.size());
+  }
+  StreamId(const StreamId&) = default;
+  StreamId& operator=(const StreamId&) = default;
+
+  bool empty() const { return value_[0] == 0; }
+  const char* data() const { return value_; }
+  size_t size() const { return strnlen(value_, kMaxSize); }
+
+  void Set(rtc::ArrayView<const uint8_t> value) {
+    Set(reinterpret_cast<const char*>(value.data()), value.size());
+  }
+  // mozilla: data() is guaranteed to be null terminated after Set completes
+  void Set(const char* data, size_t size);
+
+  friend bool operator==(const StreamId& lhs, const StreamId& rhs) {
+    return (lhs.size() == rhs.size() &&
+            strncmp(lhs.value_, rhs.value_, kMaxSize) == 0);
+  }
+  friend bool operator!=(const StreamId& lhs, const StreamId& rhs) {
+    return !(lhs == rhs);
+  }
+
+ private:
+  char value_[kMaxSize+1]; // mozilla: make sure we have space to null term.
+};
+
 struct RTPHeaderExtension {
   RTPHeaderExtension();
   RTPHeaderExtension(const RTPHeaderExtension& rhs);
   RTPHeaderExtension& operator=(const RTPHeaderExtension& rhs);
 
   bool hasTransmissionTimeOffset;
   int32_t transmissionTimeOffset;
   bool hasAbsoluteSendTime;
@@ -840,19 +880,21 @@ struct RTPHeaderExtension {
   // For Coordination of Video Orientation. See
   // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/
   // ts_126114v120700p.pdf
   bool hasVideoRotation;
   VideoRotation videoRotation;
 
   PlayoutDelay playout_delay = {-1, -1};
 
-  // RID values for simulcast; see draft-roach-avtext-rid
-  bool hasRID;
-  std::unique_ptr<char[]> rid; // UTF8 string
+  // For identification of a stream when ssrc is not signaled. See
+  // https://tools.ietf.org/html/draft-ietf-avtext-rid-09
+  // TODO(danilchap): Update url from draft to release version.
+  StreamId rtpStreamId;
+  StreamId repairedStreamId;
 };
 
 struct RTPHeader {
   RTPHeader();
 
   bool markerBit;
   uint8_t payloadType;
   uint16_t sequenceNumber;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/flexfec_sender.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/flexfec_sender.h
@@ -33,16 +33,17 @@ class RtpPacketToSend;
 // synchronization.
 
 class FlexfecSender {
  public:
   FlexfecSender(int payload_type,
                 uint32_t ssrc,
                 uint32_t protected_media_ssrc,
                 const std::vector<RtpExtension>& rtp_header_extensions,
+                rtc::ArrayView<const RtpExtensionSize> extension_sizes,
                 Clock* clock);
   ~FlexfecSender();
 
   uint32_t ssrc() const { return ssrc_; }
 
   // Sets the FEC rate, max frames sent before FEC packets are sent,
   // and what type of generator matrices are used.
   void SetFecParameters(const FecProtectionParams& params);
@@ -74,13 +75,14 @@ class FlexfecSender {
   const uint32_t ssrc_;
   const uint32_t protected_media_ssrc_;
   // Sequence number of next packet to generate.
   uint16_t seq_num_;
 
   // Implementation.
   UlpfecGenerator ulpfec_generator_;
   const RtpHeaderExtensionMap rtp_header_extension_map_;
+  const size_t header_extensions_size_;
 };
 
 }  // namespace webrtc
 
 #endif  // WEBRTC_MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -71,17 +71,18 @@ enum RTPExtensionType {
   kRtpExtensionNone,
   kRtpExtensionTransmissionTimeOffset,
   kRtpExtensionAudioLevel,
   kRtpExtensionAbsoluteSendTime,
   kRtpExtensionVideoRotation,
   kRtpExtensionTransportSequenceNumber,
   kRtpExtensionPlayoutDelay,
   kRtpExtensionRtpStreamId,
-  kRtpExtensionNumberOfExtensions,
+  kRtpExtensionRepairedRtpStreamId,
+  kRtpExtensionNumberOfExtensions  // Must be the last entity in the enum.
 };
 
 enum RTCPAppSubTypes { kAppSubtypeBwe = 0x00 };
 
 // TODO(sprang): Make this an enum class once rtcp_receiver has been cleaned up.
 enum RTCPPacketType : uint32_t {
   kRtcpReport = 0x0001,
   kRtcpSr = 0x0002,
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc
@@ -59,29 +59,32 @@ RtpHeaderExtensionMap RegisterBweExtensi
 
 }  // namespace
 
 FlexfecSender::FlexfecSender(
     int payload_type,
     uint32_t ssrc,
     uint32_t protected_media_ssrc,
     const std::vector<RtpExtension>& rtp_header_extensions,
+    rtc::ArrayView<const RtpExtensionSize> extension_sizes,
     Clock* clock)
     : clock_(clock),
       random_(clock_->TimeInMicroseconds()),
       last_generated_packet_ms_(-1),
       payload_type_(payload_type),
       // Initialize the timestamp offset and RTP sequence numbers randomly.
       // (This is not intended to be cryptographically strong.)
       timestamp_offset_(random_.Rand<uint32_t>()),
       ssrc_(ssrc),
       protected_media_ssrc_(protected_media_ssrc),
       seq_num_(random_.Rand(1, kMaxInitRtpSeqNumber)),
       ulpfec_generator_(ForwardErrorCorrection::CreateFlexfec()),
-      rtp_header_extension_map_(RegisterBweExtensions(rtp_header_extensions)) {
+      rtp_header_extension_map_(RegisterBweExtensions(rtp_header_extensions)),
+      header_extensions_size_(
+          rtp_header_extension_map_.GetTotalLengthInBytes(extension_sizes)) {
   // This object should not have been instantiated if FlexFEC is disabled.
   RTC_DCHECK_GE(payload_type, 0);
   RTC_DCHECK_LE(payload_type, 127);
 }
 
 FlexfecSender::~FlexfecSender() = default;
 
 // We are reusing the implementation from UlpfecGenerator for SetFecParameters,
@@ -143,13 +146,12 @@ std::vector<std::unique_ptr<RtpPacketToS
     last_generated_packet_ms_ = now_ms;
   }
 
   return fec_packets_to_send;
 }
 
 // The overhead is BWE RTP header extensions and FlexFEC header.
 size_t FlexfecSender::MaxPacketOverhead() const {
-  return rtp_header_extension_map_.GetTotalLengthInBytes() +
-         kFlexfecMaxHeaderSize;
+  return header_extensions_size_ + kFlexfecMaxHeaderSize;
 }
 
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
@@ -11,30 +11,34 @@
 #include <vector>
 
 #include "webrtc/config.h"
 #include "webrtc/modules/rtp_rtcp/include/flexfec_sender.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 #include "webrtc/system_wrappers/include/clock.h"
 #include "webrtc/test/gtest.h"
 
 namespace webrtc {
 
 namespace {
 
+using RtpUtility::Word32Align;
 using test::fec::AugmentedPacket;
 using test::fec::AugmentedPacketGenerator;
 
 constexpr int kFlexfecPayloadType = 123;
 constexpr uint32_t kMediaSsrc = 1234;
 constexpr uint32_t kFlexfecSsrc = 5678;
 const std::vector<RtpExtension> kNoRtpHeaderExtensions;
+const std::vector<RtpExtensionSize> kNoRtpHeaderExtensionSizes;
 // Assume a single protected media SSRC.
 constexpr size_t kFlexfecMaxHeaderSize = 32;
 constexpr size_t kPayloadLength = 50;
 
 constexpr int64_t kInitialSimulatedClockTime = 1;
 // These values are deterministically given by the PRNG, due to our fixed seed.
 // They should be updated if the PRNG implementation changes.
 constexpr uint16_t kDeterministicSequenceNumber = 28732;
@@ -68,35 +72,38 @@ std::unique_ptr<RtpPacketToSend> Generat
   return std::move(fec_packets.front());
 }
 
 }  // namespace
 
 TEST(FlexfecSenderTest, Ssrc) {
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
 
   EXPECT_EQ(kFlexfecSsrc, sender.ssrc());
 }
 
 TEST(FlexfecSenderTest, NoFecAvailableBeforeMediaAdded) {
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
 
   EXPECT_FALSE(sender.FecAvailable());
   auto fec_packets = sender.GetFecPackets();
   EXPECT_EQ(0U, fec_packets.size());
 }
 
 TEST(FlexfecSenderTest, ProtectOneFrameWithOneFecPacket) {
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size());
   EXPECT_FALSE(fec_packet->Marker());
   EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType());
   EXPECT_EQ(kDeterministicSequenceNumber, fec_packet->SequenceNumber());
   EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp());
   EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc());
@@ -108,17 +115,18 @@ TEST(FlexfecSenderTest, ProtectTwoFrames
   FecProtectionParams params;
   params.fec_rate = 15;
   params.max_fec_frames = 2;
   params.fec_mask_type = kFecMaskRandom;
   constexpr size_t kNumFrames = 2;
   constexpr size_t kNumPacketsPerFrame = 2;
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   sender.SetFecParameters(params);
 
   AugmentedPacketGenerator packet_generator(kMediaSsrc);
   for (size_t i = 0; i < kNumFrames; ++i) {
     packet_generator.NewFrame(kNumPacketsPerFrame);
     for (size_t j = 0; j < kNumPacketsPerFrame; ++j) {
       std::unique_ptr<AugmentedPacket> packet =
           packet_generator.NextPacket(i, kPayloadLength);
@@ -147,17 +155,18 @@ TEST(FlexfecSenderTest, ProtectTwoFrames
   FecProtectionParams params;
   params.fec_rate = 30;
   params.max_fec_frames = 1;
   params.fec_mask_type = kFecMaskRandom;
   constexpr size_t kNumFrames = 2;
   constexpr size_t kNumPacketsPerFrame = 2;
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   sender.SetFecParameters(params);
 
   AugmentedPacketGenerator packet_generator(kMediaSsrc);
   for (size_t i = 0; i < kNumFrames; ++i) {
     packet_generator.NewFrame(kNumPacketsPerFrame);
     for (size_t j = 0; j < kNumPacketsPerFrame; ++j) {
       std::unique_ptr<AugmentedPacket> packet =
           packet_generator.NextPacket(i, kPayloadLength);
@@ -182,79 +191,106 @@ TEST(FlexfecSenderTest, ProtectTwoFrames
   }
 }
 
 // In the tests, we only consider RTP header extensions that are useful for BWE.
 TEST(FlexfecSenderTest, NoRtpHeaderExtensionsForBweByDefault) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, RegisterAbsoluteSendTimeRtpHeaderExtension) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{
       {RtpExtension::kAbsSendTimeUri, 1}};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, RegisterTransmissionOffsetRtpHeaderExtension) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{
       {RtpExtension::kTimestampOffsetUri, 1}};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, RegisterTransportSequenceNumberRtpHeaderExtension) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{
       {RtpExtension::kTransportSequenceNumberUri, 1}};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, RegisterAllRtpHeaderExtensionsForBwe) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{
       {RtpExtension::kAbsSendTimeUri, 1},
       {RtpExtension::kTimestampOffsetUri, 2},
       {RtpExtension::kTransportSequenceNumberUri, 3}};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, MaxPacketOverhead) {
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
 
   EXPECT_EQ(kFlexfecMaxHeaderSize, sender.MaxPacketOverhead());
 }
 
+TEST(FlexfecSenderTest, MaxPacketOverheadWithExtensions) {
+  const std::vector<RtpExtension> kRtpHeaderExtensions{
+      {RtpExtension::kAbsSendTimeUri, 1},
+      {RtpExtension::kTimestampOffsetUri, 2},
+      {RtpExtension::kTransportSequenceNumberUri, 3}};
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  const size_t kExtensionHeaderLength = 1;
+  const size_t kRtpOneByteHeaderLength = 4;
+  const size_t kExtensionsTotalSize = Word32Align(
+      kRtpOneByteHeaderLength +
+      kExtensionHeaderLength + AbsoluteSendTime::kValueSizeBytes +
+      kExtensionHeaderLength + TransmissionOffset::kValueSizeBytes +
+      kExtensionHeaderLength + TransportSequenceNumber::kValueSizeBytes);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
+                       kRtpHeaderExtensions, RTPSender::FecExtensionSizes(),
+                       &clock);
+
+  EXPECT_EQ(kExtensionsTotalSize + kFlexfecMaxHeaderSize,
+            sender.MaxPacketOverhead());
+}
+
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
@@ -18,113 +18,107 @@
 
 namespace webrtc {
 namespace {
 
 using RtpUtility::Word32Align;
 
 struct ExtensionInfo {
   RTPExtensionType type;
-  size_t value_size;
   const char* uri;
 };
 
 template <typename Extension>
 constexpr ExtensionInfo CreateExtensionInfo() {
-  return {Extension::kId, Extension::kValueSizeBytes, Extension::kUri};
+  return {Extension::kId, Extension::kUri};
 }
 
 constexpr ExtensionInfo kExtensions[] = {
     CreateExtensionInfo<TransmissionOffset>(),
     CreateExtensionInfo<AudioLevel>(),
     CreateExtensionInfo<AbsoluteSendTime>(),
     CreateExtensionInfo<VideoOrientation>(),
     CreateExtensionInfo<TransportSequenceNumber>(),
     CreateExtensionInfo<PlayoutDelayLimits>(),
-    CreateExtensionInfo<StreamId>(),
+    CreateExtensionInfo<RtpStreamId>(),
+    CreateExtensionInfo<RepairedRtpStreamId>(),
 };
 
 // Because of kRtpExtensionNone, NumberOfExtension is 1 bigger than the actual
 // number of known extensions.
 static_assert(arraysize(kExtensions) ==
                   static_cast<int>(kRtpExtensionNumberOfExtensions) - 1,
               "kExtensions expect to list all known extensions");
 
-size_t ValueSize(RTPExtensionType type) {
-  for (const ExtensionInfo& extension : kExtensions)
-    if (type == extension.type)
-      return extension.value_size;
-
-  RTC_NOTREACHED();
-  return 0;
-}
-
 }  // namespace
 
 constexpr RTPExtensionType RtpHeaderExtensionMap::kInvalidType;
 constexpr uint8_t RtpHeaderExtensionMap::kInvalidId;
 constexpr uint8_t RtpHeaderExtensionMap::kMinId;
 constexpr uint8_t RtpHeaderExtensionMap::kMaxId;
 
 RtpHeaderExtensionMap::RtpHeaderExtensionMap() {
-  total_values_size_bytes_ = 0;
   for (auto& type : types_)
     type = kInvalidType;
   for (auto& id : ids_)
     id = kInvalidId;
 }
 
 RtpHeaderExtensionMap::RtpHeaderExtensionMap(
     rtc::ArrayView<const RtpExtension> extensions)
     : RtpHeaderExtensionMap() {
   for (const RtpExtension& extension : extensions)
     RegisterByUri(extension.id, extension.uri);
 }
 
 bool RtpHeaderExtensionMap::RegisterByType(uint8_t id, RTPExtensionType type) {
   for (const ExtensionInfo& extension : kExtensions)
     if (type == extension.type)
-      return Register(id, extension.type, extension.value_size, extension.uri);
+      return Register(id, extension.type, extension.uri);
   RTC_NOTREACHED();
   return false;
 }
 
 bool RtpHeaderExtensionMap::RegisterByUri(uint8_t id, const std::string& uri) {
   for (const ExtensionInfo& extension : kExtensions)
     if (uri == extension.uri)
-      return Register(id, extension.type, extension.value_size, extension.uri);
+      return Register(id, extension.type, extension.uri);
   LOG(LS_WARNING) << "Unknown extension uri:'" << uri
                   << "', id: " << static_cast<int>(id) << '.';
   return false;
 }
 
-size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const {
-  if (total_values_size_bytes_ == 0)
+size_t RtpHeaderExtensionMap::GetTotalLengthInBytes(
+    rtc::ArrayView<const RtpExtensionSize> extensions) const {
+  // Header size of each individual extension, see RFC5285 Section 4.2
+  static constexpr size_t kExtensionHeaderLength = 1;
+  size_t values_size = 0;
+  for (const RtpExtensionSize& extension : extensions) {
+    if (IsRegistered(extension.type))
+      values_size += extension.value_size + kExtensionHeaderLength;
+  }
+  if (values_size == 0)
     return 0;
-  return Word32Align(kRtpOneByteHeaderLength + total_values_size_bytes_);
+  return Word32Align(kRtpOneByteHeaderLength + values_size);
 }
 
 int32_t RtpHeaderExtensionMap::Deregister(RTPExtensionType type) {
   if (IsRegistered(type)) {
     uint8_t id = GetId(type);
-    total_values_size_bytes_ -= (ValueSize(type) + 1);
     types_[id] = kInvalidType;
     ids_[type] = kInvalidId;
   }
   return 0;
 }
 
 bool RtpHeaderExtensionMap::Register(uint8_t id,
                                      RTPExtensionType type,
-                                     size_t value_size,
                                      const char* uri) {
   RTC_DCHECK_GT(type, kRtpExtensionNone);
   RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions);
-  RTC_DCHECK_GE(value_size, 1U);
-  RTC_DCHECK_LE(value_size, 16U);
 
   if (id < kMinId || id > kMaxId) {
     LOG(LS_WARNING) << "Failed to register extension uri:'" << uri
                     << "' with invalid id:" << static_cast<int>(id) << ".";
     return false;
   }
 
   if (GetType(id) == type) {  // Same type/id pair already registered.
@@ -139,13 +133,12 @@ bool RtpHeaderExtensionMap::Register(uin
                     << ". Id already in use by extension type "
                     << static_cast<int>(GetType(id));
     return false;
   }
   RTC_DCHECK(!IsRegistered(type));
 
   types_[id] = type;
   ids_[type] = id;
-  total_values_size_bytes_ += (value_size + 1);
   return true;
 }
 
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
@@ -17,46 +17,41 @@
 #include "webrtc/base/basictypes.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/config.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 
 namespace webrtc {
 
 const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE;
-
 const size_t kRtpOneByteHeaderLength = 4;
-const size_t kTransmissionTimeOffsetLength = 4;
-const size_t kAudioLevelLength = 2;
-const size_t kAbsoluteSendTimeLength = 4;
-const size_t kVideoRotationLength = 2;
-const size_t kTransportSequenceNumberLength = 3;
-const size_t kPlayoutDelayLength = 4;
-// kRtpStreamIdLength is variable
-const size_t kRtpStreamIdLength = 4; // max 1-byte header extension length
 
 // Playout delay in milliseconds. A playout delay limit (min or max)
 // has 12 bits allocated. This allows a range of 0-4095 values which translates
 // to a range of 0-40950 in milliseconds.
 const int kPlayoutDelayGranularityMs = 10;
 // Maximum playout delay value in milliseconds.
 const int kPlayoutDelayMaxMs = 40950;
 
+struct RtpExtensionSize {
+  RTPExtensionType type;
+  uint8_t value_size;
+};
+
 class RtpHeaderExtensionMap {
  public:
   static constexpr RTPExtensionType kInvalidType = kRtpExtensionNone;
   static constexpr uint8_t kInvalidId = 0;
 
   RtpHeaderExtensionMap();
   explicit RtpHeaderExtensionMap(rtc::ArrayView<const RtpExtension> extensions);
 
   template <typename Extension>
   bool Register(uint8_t id) {
-    return Register(id, Extension::kId, Extension::kValueSizeBytes,
-                    Extension::kUri);
+    return Register(id, Extension::kId, Extension::kUri);
   }
   bool RegisterByType(uint8_t id, RTPExtensionType type);
   bool RegisterByUri(uint8_t id, const std::string& uri);
 
   bool IsRegistered(RTPExtensionType type) const {
     return GetId(type) != kInvalidId;
   }
   // Return kInvalidType if not found.
@@ -67,33 +62,30 @@ class RtpHeaderExtensionMap {
   }
   // Return kInvalidId if not found.
   uint8_t GetId(RTPExtensionType type) const {
     RTC_DCHECK_GT(type, kRtpExtensionNone);
     RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions);
     return ids_[type];
   }
 
-  size_t GetTotalLengthInBytes() const;
+  size_t GetTotalLengthInBytes(
+      rtc::ArrayView<const RtpExtensionSize> extensions) const;
 
   // TODO(danilchap): Remove use of the functions below.
   int32_t Register(RTPExtensionType type, uint8_t id) {
     return RegisterByType(id, type) ? 0 : -1;
   }
   int32_t Deregister(RTPExtensionType type);
 
  private:
   static constexpr uint8_t kMinId = 1;
   static constexpr uint8_t kMaxId = 14;
-  bool Register(uint8_t id,
-                RTPExtensionType type,
-                size_t value_size,
-                const char* uri);
+  bool Register(uint8_t id, RTPExtensionType type, const char* uri);
 
-  size_t total_values_size_bytes_ = 0;
   RTPExtensionType types_[kMaxId + 1];
   uint8_t ids_[kRtpExtensionNumberOfExtensions];
 };
 
 }  // namespace webrtc
 
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSION_H_
 
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc
@@ -80,20 +80,22 @@ TEST(RtpHeaderExtensionTest, NonUniqueId
   EXPECT_TRUE(map.Register<TransmissionOffset>(3));
 
   EXPECT_FALSE(map.Register<AudioLevel>(3));
   EXPECT_TRUE(map.Register<AudioLevel>(4));
 }
 
 TEST(RtpHeaderExtensionTest, GetTotalLength) {
   RtpHeaderExtensionMap map;
-  EXPECT_EQ(0u, map.GetTotalLengthInBytes());
+  constexpr RtpExtensionSize kExtensionSizes[] = {
+      {TransmissionOffset::kId, TransmissionOffset::kValueSizeBytes}};
+  EXPECT_EQ(0u, map.GetTotalLengthInBytes(kExtensionSizes));
   EXPECT_TRUE(map.Register<TransmissionOffset>(3));
   EXPECT_EQ(kRtpOneByteHeaderLength + (TransmissionOffset::kValueSizeBytes + 1),
-            map.GetTotalLengthInBytes());
+            map.GetTotalLengthInBytes(kExtensionSizes));
 }
 
 TEST(RtpHeaderExtensionTest, GetType) {
   RtpHeaderExtensionMap map;
   EXPECT_EQ(RtpHeaderExtensionMap::kInvalidType, map.GetType(3));
   EXPECT_TRUE(map.Register<TransmissionOffset>(3));
 
   EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -30,23 +30,27 @@ namespace webrtc {
 //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //   |  ID   | len=2 |              absolute send time               |
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType AbsoluteSendTime::kId;
 constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
 constexpr const char* AbsoluteSendTime::kUri;
 
-bool AbsoluteSendTime::Parse(const uint8_t* data, uint32_t* time_24bits) {
-  *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data);
+bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
+                             uint32_t* time_24bits) {
+  if (data.size() != 3)
+    return false;
+  *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
   return true;
 }
 
-bool AbsoluteSendTime::Write(uint8_t* data, int64_t time_ms) {
-  ByteWriter<uint32_t, 3>::WriteBigEndian(data, MsTo24Bits(time_ms));
+bool AbsoluteSendTime::Write(uint8_t* data, uint32_t time_24bits) {
+  RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
+  ByteWriter<uint32_t, 3>::WriteBigEndian(data, time_24bits);
   return true;
 }
 
 // An RTP Header Extension for Client-to-Mixer Audio Level Indication
 //
 // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
 //
 // The form of the audio level extension block:
@@ -56,19 +60,21 @@ bool AbsoluteSendTime::Write(uint8_t* da
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //   |  ID   | len=0 |V|   level     |
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //
 constexpr RTPExtensionType AudioLevel::kId;
 constexpr uint8_t AudioLevel::kValueSizeBytes;
 constexpr const char* AudioLevel::kUri;
 
-bool AudioLevel::Parse(const uint8_t* data,
+bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
                        bool* voice_activity,
                        uint8_t* audio_level) {
+  if (data.size() != 1)
+    return false;
   *voice_activity = (data[0] & 0x80) != 0;
   *audio_level = data[0] & 0x7F;
   return true;
 }
 
 bool AudioLevel::Write(uint8_t* data,
                        bool voice_activity,
                        uint8_t audio_level) {
@@ -92,18 +98,21 @@ bool AudioLevel::Write(uint8_t* data,
 //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //   |  ID   | len=2 |              transmission offset              |
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType TransmissionOffset::kId;
 constexpr uint8_t TransmissionOffset::kValueSizeBytes;
 constexpr const char* TransmissionOffset::kUri;
 
-bool TransmissionOffset::Parse(const uint8_t* data, int32_t* rtp_time) {
-  *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data);
+bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
+                               int32_t* rtp_time) {
+  if (data.size() != 3)
+    return false;
+  *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
   return true;
 }
 
 bool TransmissionOffset::Write(uint8_t* data, int32_t rtp_time) {
   RTC_DCHECK_LE(rtp_time, 0x00ffffff);
   ByteWriter<int32_t, 3>::WriteBigEndian(data, rtp_time);
   return true;
 }
@@ -112,18 +121,21 @@ bool TransmissionOffset::Write(uint8_t* 
 //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //  |  ID   | L=1   |transport wide sequence number |
 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType TransportSequenceNumber::kId;
 constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
 constexpr const char* TransportSequenceNumber::kUri;
 
-bool TransportSequenceNumber::Parse(const uint8_t* data, uint16_t* value) {
-  *value = ByteReader<uint16_t>::ReadBigEndian(data);
+bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
+                                    uint16_t* value) {
+  if (data.size() != 2)
+    return false;
+  *value = ByteReader<uint16_t>::ReadBigEndian(data.data());
   return true;
 }
 
 bool TransportSequenceNumber::Write(uint8_t* data, uint16_t value) {
   ByteWriter<uint16_t>::WriteBigEndian(data, value);
   return true;
 }
 
@@ -137,27 +149,33 @@ bool TransportSequenceNumber::Write(uint
 //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //   |  ID   | len=0 |0 0 0 0 C F R R|
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType VideoOrientation::kId;
 constexpr uint8_t VideoOrientation::kValueSizeBytes;
 constexpr const char* VideoOrientation::kUri;
 
-bool VideoOrientation::Parse(const uint8_t* data, VideoRotation* rotation) {
+bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
+                             VideoRotation* rotation) {
+  if (data.size() != 1)
+    return false;
   *rotation = ConvertCVOByteToVideoRotation(data[0]);
   return true;
 }
 
 bool VideoOrientation::Write(uint8_t* data, VideoRotation rotation) {
   data[0] = ConvertVideoRotationToCVOByte(rotation);
   return true;
 }
 
-bool VideoOrientation::Parse(const uint8_t* data, uint8_t* value) {
+bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
+                             uint8_t* value) {
+  if (data.size() != 1)
+    return false;
   *value = data[0];
   return true;
 }
 
 bool VideoOrientation::Write(uint8_t* data, uint8_t value) {
   data[0] = value;
   return true;
 }
@@ -166,20 +184,22 @@ bool VideoOrientation::Write(uint8_t* da
 //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //  |  ID   | len=2 |   MIN delay           |   MAX delay           |
 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType PlayoutDelayLimits::kId;
 constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
 constexpr const char* PlayoutDelayLimits::kUri;
 
-bool PlayoutDelayLimits::Parse(const uint8_t* data,
+bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
                                PlayoutDelay* playout_delay) {
   RTC_DCHECK(playout_delay);
-  uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data);
+  if (data.size() != 3)
+    return false;
+  uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
   uint16_t min_raw = (raw >> 12);
   uint16_t max_raw = (raw & 0xfff);
   if (min_raw > max_raw)
     return false;
   playout_delay->min_ms = min_raw * kGranularityMs;
   playout_delay->max_ms = max_raw * kGranularityMs;
   return true;
 }
@@ -191,40 +211,81 @@ bool PlayoutDelayLimits::Write(uint8_t* 
   RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
   // Convert MS to value to be sent on extension header.
   uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
   uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
   ByteWriter<uint32_t, 3>::WriteBigEndian(data, (min_delay << 12) | max_delay);
   return true;
 }
 
-//   0                   1                   2
-//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |  ID   | L=?   |UTF-8 RID value......          |...
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-constexpr RTPExtensionType StreamId::kId;
-constexpr uint8_t StreamId::kValueSizeBytes;
-constexpr const char* StreamId::kUri;
+// RtpStreamId.
+constexpr RTPExtensionType RtpStreamId::kId;
+constexpr const char* RtpStreamId::kUri;
+
+bool RtpStreamId::Parse(rtc::ArrayView<const uint8_t> data, StreamId* rsid) {
+  if (data.empty() || data[0] == 0 ||  // Valid rsid can't be empty.
+      data.size() <= StreamId::kMaxSize) // mozilla
+    return false;
+  // If there is a \0 character in the middle of the |data|, it will be treated
+  // as the end of the StreamId when StreamId::size() is called.
+  rsid->Set(data);
+  RTC_DCHECK(!rsid->empty());
+  return true;
+}
 
-bool StreamId::Parse(const uint8_t* data, char rid[kRIDSize+1]) {
-  uint8_t len = (data[0] & 0x0F) + 1;
-  memcpy(rid, &data[1], len);
-  rid[len] = '\0';
+bool RtpStreamId::Write(uint8_t* data, const StreamId& rsid) {
+  RTC_DCHECK_GE(rsid.size(), 1);
+  RTC_DCHECK_LE(rsid.size(), StreamId::kMaxSize);
+  memcpy(data, rsid.data(), rsid.size());
+  return true;
+}
+
+bool RtpStreamId::Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid) {
+  if (data.empty() || data[0] == 0 ||  // Valid rsid can't be empty.
+      data.size() <= StreamId::kMaxSize) // mozilla
+    return false;
+  const char* str = reinterpret_cast<const char*>(data.data());
+  // If there is a \0 character in the middle of the |data|, treat it as end of
+  // the string. Well-formed rsid shouldn't contain it.
+  rsid->assign(str, strnlen(str, data.size()));
+  RTC_DCHECK(!rsid->empty());
   return true;
 }
 
-bool StreamId::Write(uint8_t* data, const char *rid) {
-  // XXX FIX!  how to get it to modify the length?  data points to the RID value
-  int len = strlen(rid);
-  RTC_DCHECK(len > 0 && len <= 16);
-  if (len > 16) {
-    len = 16;
-  } else if (len == 0) {
-    // really bad, but don't blow up
-    rid = "x";
-    len = 1;
-  }
-  memcpy(data, rid, len);
+bool RtpStreamId::Write(uint8_t* data, const std::string& rsid) {
+  RTC_DCHECK_GE(rsid.size(), 1);
+  RTC_DCHECK_LE(rsid.size(), StreamId::kMaxSize);
+  memcpy(data, rsid.data(), rsid.size());
   return true;
 }
 
+// RepairedRtpStreamId.
+constexpr RTPExtensionType RepairedRtpStreamId::kId;
+constexpr const char* RepairedRtpStreamId::kUri;
+
+// RtpStreamId and RepairedRtpStreamId use the same format to store rsid.
+bool RepairedRtpStreamId::Parse(rtc::ArrayView<const uint8_t> data,
+                                StreamId* rsid) {
+  return RtpStreamId::Parse(data, rsid);
+}
+
+size_t RepairedRtpStreamId::ValueSize(const StreamId& rsid) {
+  return RtpStreamId::ValueSize(rsid);
+}
+
+bool RepairedRtpStreamId::Write(uint8_t* data, const StreamId& rsid) {
+  return RtpStreamId::Write(data, rsid);
+}
+
+bool RepairedRtpStreamId::Parse(rtc::ArrayView<const uint8_t> data,
+                                std::string* rsid) {
+  return RtpStreamId::Parse(data, rsid);
+}
+
+size_t RepairedRtpStreamId::ValueSize(const std::string& rsid) {
+  return RtpStreamId::ValueSize(rsid);
+}
+
+bool RepairedRtpStreamId::Write(uint8_t* data, const std::string& rsid) {
+  return RtpStreamId::Write(data, rsid);
+}
+
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -20,67 +20,75 @@ namespace webrtc {
 
 class AbsoluteSendTime {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionAbsoluteSendTime;
   static constexpr uint8_t kValueSizeBytes = 3;
   static constexpr const char* kUri =
       "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
 
-  static bool Parse(const uint8_t* data, uint32_t* time_24bits);
-  static bool Write(uint8_t* data, int64_t time_ms);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, uint32_t* time_24bits);
+  static size_t ValueSize(uint32_t time_24bits) { return kValueSizeBytes; }
+  static bool Write(uint8_t* data, uint32_t time_24bits);
 
   static constexpr uint32_t MsTo24Bits(int64_t time_ms) {
     return static_cast<uint32_t>(((time_ms << 18) + 500) / 1000) & 0x00FFFFFF;
   }
 };
 
 class AudioLevel {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionAudioLevel;
   static constexpr uint8_t kValueSizeBytes = 1;
   static constexpr const char* kUri =
       "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
 
-  static bool Parse(const uint8_t* data,
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
                     bool* voice_activity,
                     uint8_t* audio_level);
+  static size_t ValueSize(bool voice_activity, uint8_t audio_level) {
+    return kValueSizeBytes;
+  }
   static bool Write(uint8_t* data, bool voice_activity, uint8_t audio_level);
 };
 
 class TransmissionOffset {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionTransmissionTimeOffset;
   static constexpr uint8_t kValueSizeBytes = 3;
   static constexpr const char* kUri = "urn:ietf:params:rtp-hdrext:toffset";
 
-  static bool Parse(const uint8_t* data, int32_t* rtp_time);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, int32_t* rtp_time);
+  static size_t ValueSize(int32_t rtp_time) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, int32_t rtp_time);
 };
 
 class TransportSequenceNumber {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionTransportSequenceNumber;
   static constexpr uint8_t kValueSizeBytes = 2;
   static constexpr const char* kUri =
       "http://www.ietf.org/id/"
       "draft-holmer-rmcat-transport-wide-cc-extensions-01";
-  static bool Parse(const uint8_t* data, uint16_t* value);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, uint16_t* value);
+  static size_t ValueSize(uint16_t value) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, uint16_t value);
 };
 
 class VideoOrientation {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionVideoRotation;
   static constexpr uint8_t kValueSizeBytes = 1;
   static constexpr const char* kUri = "urn:3gpp:video-orientation";
 
-  static bool Parse(const uint8_t* data, VideoRotation* value);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, VideoRotation* value);
+  static size_t ValueSize(VideoRotation) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, VideoRotation value);
-  static bool Parse(const uint8_t* data, uint8_t* value);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, uint8_t* value);
+  static size_t ValueSize(uint8_t value) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, uint8_t value);
 };
 
 class PlayoutDelayLimits {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionPlayoutDelay;
   static constexpr uint8_t kValueSizeBytes = 3;
   static constexpr const char* kUri =
@@ -88,24 +96,46 @@ class PlayoutDelayLimits {
 
   // Playout delay in milliseconds. A playout delay limit (min or max)
   // has 12 bits allocated. This allows a range of 0-4095 values which
   // translates to a range of 0-40950 in milliseconds.
   static constexpr int kGranularityMs = 10;
   // Maximum playout delay value in milliseconds.
   static constexpr int kMaxMs = 0xfff * kGranularityMs;  // 40950.
 
-  static bool Parse(const uint8_t* data, PlayoutDelay* playout_delay);
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    PlayoutDelay* playout_delay);
+  static size_t ValueSize(const PlayoutDelay&) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, const PlayoutDelay& playout_delay);
 };
 
-class StreamId {
+class RtpStreamId {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionRtpStreamId;
-  static constexpr uint8_t kValueSizeBytes = 1; // variable! we add the RID length to this
-  static constexpr const char* kUri = "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
+  static constexpr const char* kUri =
+      "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, StreamId* rsid);
+  static size_t ValueSize(const StreamId& rsid) { return rsid.size(); }
+  static bool Write(uint8_t* data, const StreamId& rsid);
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid);
+  static size_t ValueSize(const std::string& rsid) { return rsid.size(); }
+  static bool Write(uint8_t* data, const std::string& rsid);
+};
 
-  static bool Parse(const uint8_t* data, char rid[kRIDSize+1]);
-  static bool Write(uint8_t* data, const char *rid); // 1-16 bytes
+class RepairedRtpStreamId {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionRepairedRtpStreamId;
+  static constexpr const char* kUri =
+      "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, StreamId* rsid);
+  static size_t ValueSize(const StreamId& rsid);
+  static bool Write(uint8_t* data, const StreamId& rsid);
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid);
+  static size_t ValueSize(const std::string& rsid);
+  static bool Write(uint8_t* data, const std::string& rsid);
 };
 
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
@@ -13,28 +13,33 @@
 #include <cstring>
 #include <utility>
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/random.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
-#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 
 namespace webrtc {
 namespace rtp {
 namespace {
 constexpr size_t kFixedHeaderSize = 12;
 constexpr uint8_t kRtpVersion = 2;
 constexpr uint16_t kOneByteExtensionId = 0xBEDE;
 constexpr size_t kOneByteHeaderSize = 1;
 constexpr size_t kDefaultPacketSize = 1500;
 }  // namespace
+
+constexpr size_t Packet::kMaxExtensionHeaders;
+constexpr int Packet::kMinExtensionId;
+constexpr int Packet::kMaxExtensionId;
+
 //  0                   1                   2                   3
 //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 // |V=2|P|X|  CC   |M|     PT      |       sequence number         |
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 // |                           timestamp                           |
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 // |           synchronization source (SSRC) identifier            |
@@ -52,16 +57,18 @@ constexpr size_t kDefaultPacketSize = 15
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 // |               padding         | Padding size  |
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 Packet::Packet() : Packet(nullptr, kDefaultPacketSize) {}
 
 Packet::Packet(const ExtensionManager* extensions)
     : Packet(extensions, kDefaultPacketSize) {}
 
+Packet::Packet(const Packet&) = default;
+
 Packet::Packet(const ExtensionManager* extensions, size_t capacity)
     : buffer_(capacity) {
   RTC_DCHECK_GE(capacity, kFixedHeaderSize);
   Clear();
   if (extensions) {
     IdentifyExtensions(*extensions);
   } else {
     for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
@@ -159,16 +166,19 @@ void Packet::GetHeader(RTPHeader* header
       GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
   header->extension.hasTransportSequenceNumber =
       GetExtension<TransportSequenceNumber>(
           &header->extension.transportSequenceNumber);
   header->extension.hasAudioLevel = GetExtension<AudioLevel>(
       &header->extension.voiceActivity, &header->extension.audioLevel);
   header->extension.hasVideoRotation =
       GetExtension<VideoOrientation>(&header->extension.videoRotation);
+  GetExtension<RtpStreamId>(&header->extension.rtpStreamId);
+  GetExtension<RepairedRtpStreamId>(&header->extension.repairedStreamId);
+  GetExtension<PlayoutDelayLimits>(&header->extension.playout_delay);
 }
 
 size_t Packet::headers_size() const {
   return payload_offset_;
 }
 
 size_t Packet::payload_size() const {
   return payload_size_;
@@ -268,37 +278,131 @@ void Packet::SetCsrcs(const std::vector<
   size_t offset = kFixedHeaderSize;
   for (uint32_t csrc : csrcs) {
     ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
     offset += 4;
   }
   buffer_.SetSize(payload_offset_);
 }
 
+bool Packet::HasRawExtension(int id) const {
+  if (id == ExtensionManager::kInvalidId)
+    return false;
+  RTC_DCHECK_GE(id, kMinExtensionId);
+  RTC_DCHECK_LE(id, kMaxExtensionId);
+  return extension_entries_[id - 1].offset != 0;
+}
+
+rtc::ArrayView<const uint8_t> Packet::GetRawExtension(int id) const {
+  if (id == ExtensionManager::kInvalidId)
+    return nullptr;
+  RTC_DCHECK_GE(id, kMinExtensionId);
+  RTC_DCHECK_LE(id, kMaxExtensionId);
+  const ExtensionInfo& extension = extension_entries_[id - 1];
+  if (extension.offset == 0)
+    return nullptr;
+  return rtc::MakeArrayView(data() + extension.offset, extension.length);
+}
+
+bool Packet::SetRawExtension(int id, rtc::ArrayView<const uint8_t> data) {
+  auto buffer = AllocateRawExtension(id, data.size());
+  if (buffer.empty())
+    return false;
+  RTC_DCHECK_EQ(buffer.size(), data.size());
+  memcpy(buffer.data(), data.data(), data.size());
+  return true;
+}
+
+rtc::ArrayView<uint8_t> Packet::AllocateRawExtension(int id, size_t length) {
+  if (id == ExtensionManager::kInvalidId)
+    return nullptr;
+  RTC_DCHECK_GE(id, kMinExtensionId);
+  RTC_DCHECK_LE(id, kMaxExtensionId);
+  RTC_DCHECK_GE(length, 1);
+  RTC_DCHECK_LE(length, 16);
+
+  ExtensionInfo* extension_entry = &extension_entries_[id - 1];
+  if (extension_entry->offset != 0) {
+    // Extension already reserved. Check if same length is used.
+    if (extension_entry->length == length)
+      return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
+
+    LOG(LS_ERROR) << "Length mismatch for extension id " << id << " type "
+                  << static_cast<int>(extension_entry->type) << ": expected "
+                  << static_cast<int>(extension_entry->length) << ". received "
+                  << length;
+    return nullptr;
+  }
+  if (payload_size_ > 0) {
+    LOG(LS_ERROR) << "Can't add new extension id " << id
+                  << " after payload was set.";
+    return nullptr;
+  }
+  if (padding_size_ > 0) {
+    LOG(LS_ERROR) << "Can't add new extension id " << id
+                  << " after padding was set.";
+    return nullptr;
+  }
+
+  size_t num_csrc = data()[0] & 0x0F;
+  size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
+  size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length;
+  if (extensions_offset + new_extensions_size > capacity()) {
+    LOG(LS_ERROR)
+        << "Extension cannot be registered: Not enough space left in buffer.";
+    return nullptr;
+  }
+
+  // All checks passed, write down the extension headers.
+  if (extensions_size_ == 0) {
+    RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
+    WriteAt(0, data()[0] | 0x10);  // Set extension bit.
+    // Profile specific ID always set to OneByteExtensionHeader.
+    ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
+                                         kOneByteExtensionId);
+  }
+
+  WriteAt(extensions_offset + extensions_size_, (id << 4) | (length - 1));
+
+  extension_entry->offset =
+      extensions_offset + extensions_size_ + kOneByteHeaderSize;
+  extension_entry->length = length;
+  extensions_size_ = new_extensions_size;
+
+  // Update header length field.
+  uint16_t extensions_words = (extensions_size_ + 3) / 4;  // Wrap up to 32bit.
+  ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
+                                       extensions_words);
+  // Fill extension padding place with zeroes.
+  size_t extension_padding_size = 4 * extensions_words - extensions_size_;
+  memset(WriteAt(extensions_offset + extensions_size_), 0,
+         extension_padding_size);
+  payload_offset_ = extensions_offset + 4 * extensions_words;
+  buffer_.SetSize(payload_offset_);
+  return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
+}
+
 uint8_t* Packet::AllocatePayload(size_t size_bytes) {
+  // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
+  // reallocation and memcpy. Keeping just header reduces memcpy size.
+  SetPayloadSize(0);
+  return SetPayloadSize(size_bytes);
+}
+
+uint8_t* Packet::SetPayloadSize(size_t size_bytes) {
   RTC_DCHECK_EQ(padding_size_, 0);
   if (payload_offset_ + size_bytes > capacity()) {
     LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
     return nullptr;
   }
-  // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
-  // reallocation and memcpy. Setting size to just headers reduces memcpy size.
-  buffer_.SetSize(payload_offset_);
   payload_size_ = size_bytes;
   buffer_.SetSize(payload_offset_ + payload_size_);
   return WriteAt(payload_offset_);
 }
 
-void Packet::SetPayloadSize(size_t size_bytes) {
-  RTC_DCHECK_EQ(padding_size_, 0);
-  RTC_DCHECK_LE(size_bytes, payload_size_);
-  payload_size_ = size_bytes;
-  buffer_.SetSize(payload_offset_ + payload_size_);
-}
-
 bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
   RTC_DCHECK(random);
   if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
     LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
                     << (capacity() - payload_offset_ - payload_size_)
                     << " bytes left in buffer.";
     return false;
   }
@@ -435,119 +539,39 @@ bool Packet::ParseBuffer(const uint8_t* 
 
   if (payload_offset_ + padding_size_ > size) {
     return false;
   }
   payload_size_ = size - payload_offset_ - padding_size_;
   return true;
 }
 
-bool Packet::FindExtension(ExtensionType type,
-                           uint8_t length,
-                           uint16_t* offset) const {
-  RTC_DCHECK(offset);
+rtc::ArrayView<const uint8_t> Packet::FindExtension(ExtensionType type) const {
   for (const ExtensionInfo& extension : extension_entries_) {
     if (extension.type == type) {
       if (extension.length == 0) {
         // Extension is registered but not set.
-        return false;
-      }
-      if (length != extension.length) {
-        LOG(LS_WARNING) << "Length mismatch for extension '" << type
-                        << "': expected " << static_cast<int>(length)
-                        << ", received " << static_cast<int>(extension.length);
-        return false;
+        return nullptr;
       }
-      *offset = extension.offset;
-      return true;
-    }
-  }
-  return false;
-}
-
-bool Packet::AllocateExtension(ExtensionType type,
-                               uint8_t length,
-                               uint16_t* offset) {
-  uint8_t extension_id = ExtensionManager::kInvalidId;
-  ExtensionInfo* extension_entry = nullptr;
-  for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
-    if (extension_entries_[i].type == type) {
-      extension_id = i + 1;
-      extension_entry = &extension_entries_[i];
-      break;
+      return rtc::MakeArrayView(data() + extension.offset, extension.length);
     }
   }
-
-  if (!extension_entry)  // Extension not registered.
-    return false;
-
-  if (extension_entry->length != 0) {  // Already allocated.
-    if (length != extension_entry->length) {
-      LOG(LS_WARNING) << "Length mismatch for extension '" << type
-                      << "': expected " << static_cast<int>(length)
-                      << ", received "
-                      << static_cast<int>(extension_entry->length);
-      return false;
-    }
-    *offset = extension_entry->offset;
-    return true;
-  }
-
-  // Can't add new extension after payload/padding was set.
-  if (payload_size_ > 0) {
-    return false;
-  }
-  if (padding_size_ > 0) {
-    return false;
-  }
-
-  RTC_DCHECK_GT(length, 0);
-  RTC_DCHECK_LE(length, 16);
+  return nullptr;
+}
 
-  size_t num_csrc = data()[0] & 0x0F;
-  size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
-  if (extensions_offset + extensions_size_ + kOneByteHeaderSize + length >
-      capacity()) {
-    LOG(LS_WARNING) << "Extension cannot be registered: "
-                       "Not enough space left in buffer.";
-    return false;
+rtc::ArrayView<uint8_t> Packet::AllocateExtension(ExtensionType type,
+                                                  size_t length) {
+  for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
+    if (extension_entries_[i].type == type) {
+      int extension_id = i + 1;
+      return AllocateRawExtension(extension_id, length);
+    }
   }
-
-  uint16_t new_extensions_size =
-      extensions_size_ + kOneByteHeaderSize + length;
-  uint16_t extensions_words =
-      (new_extensions_size + 3) / 4;  // Wrap up to 32bit.
-
-  // All checks passed, write down the extension.
-  if (extensions_size_ == 0) {
-    RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
-    WriteAt(0, data()[0] | 0x10);  // Set extension bit.
-    // Profile specific ID always set to OneByteExtensionHeader.
-    ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
-                                         kOneByteExtensionId);
-  }
-
-  WriteAt(extensions_offset + extensions_size_,
-          (extension_id << 4) | (length - 1));
-
-  extension_entry->length = length;
-  *offset = extensions_offset + kOneByteHeaderSize + extensions_size_;
-  extension_entry->offset = *offset;
-  extensions_size_ = new_extensions_size;
-
-  // Update header length field.
-  ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
-                                       extensions_words);
-  // Fill extension padding place with zeroes.
-  size_t extension_padding_size = 4 * extensions_words - extensions_size_;
-  memset(WriteAt(extensions_offset + extensions_size_), 0,
-         extension_padding_size);
-  payload_offset_ = extensions_offset + 4 * extensions_words;
-  buffer_.SetSize(payload_offset_);
-  return true;
+  // Extension not registered.
+  return nullptr;
 }
 
 uint8_t* Packet::WriteAt(size_t offset) {
   return buffer_.data() + offset;
 }
 
 void Packet::WriteAt(size_t offset, uint8_t byte) {
   buffer_.data()[offset] = byte;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.h
@@ -23,16 +23,18 @@ class RtpHeaderExtensionMap;
 class Random;
 
 namespace rtp {
 class Packet {
  public:
   using ExtensionType = RTPExtensionType;
   using ExtensionManager = RtpHeaderExtensionMap;
   static constexpr size_t kMaxExtensionHeaders = 14;
+  static constexpr int kMinExtensionId = 1;
+  static constexpr int kMaxExtensionId = 14;
 
   // Parse and copy given buffer into Packet.
   bool Parse(const uint8_t* buffer, size_t size);
   bool Parse(rtc::ArrayView<const uint8_t> packet);
 
   // Parse and move given buffer into Packet.
   bool Parse(rtc::CopyOnWriteBuffer packet);
 
@@ -86,67 +88,72 @@ class Packet {
   template <typename Extension>
   bool HasExtension() const;
 
   template <typename Extension, typename... Values>
   bool GetExtension(Values...) const;
 
   template <typename Extension, typename... Values>
   bool SetExtension(Values...);
-  template <typename Extension, typename... Values>
-  bool SetExtensionWithLength(size_t length, Values...);
 
   template <typename Extension>
   bool ReserveExtension();
 
+  // Following 4 helpers identify rtp header extension by |id| negotiated with
+  // remote peer and written in an rtp packet.
+  bool HasRawExtension(int id) const;
+
+  // Returns place where extension with |id| is stored.
+  // Returns empty arrayview if extension is not present.
+  rtc::ArrayView<const uint8_t> GetRawExtension(int id) const;
+
+  // Allocates and store header extension. Returns true on success.
+  bool SetRawExtension(int id, rtc::ArrayView<const uint8_t> data);
+
+  // Allocates and returns place to store rtp header extension.
+  // Returns empty arrayview on failure.
+  rtc::ArrayView<uint8_t> AllocateRawExtension(int id, size_t length);
+
   // Reserve size_bytes for payload. Returns nullptr on failure.
+  uint8_t* SetPayloadSize(size_t size_bytes);
+  // Same as SetPayloadSize but doesn't guarantee to keep current payload.
   uint8_t* AllocatePayload(size_t size_bytes);
-  void SetPayloadSize(size_t size_bytes);
   bool SetPadding(uint8_t size_bytes, Random* random);
 
  protected:
   // |extensions| required for SetExtension/ReserveExtension functions during
   // packet creating and used if available in Parse function.
   // Adding and getting extensions will fail until |extensions| is
   // provided via constructor or IdentifyExtensions function.
   Packet();
   explicit Packet(const ExtensionManager* extensions);
-  Packet(const Packet&) = default;
+  Packet(const Packet&);
   Packet(const ExtensionManager* extensions, size_t capacity);
   virtual ~Packet();
 
   Packet& operator=(const Packet&) = default;
 
  private:
   struct ExtensionInfo {
     ExtensionType type;
     uint16_t offset;
     uint8_t length;
   };
 
   // Helper function for Parse. Fill header fields using data in given buffer,
   // but does not touch packet own buffer, leaving packet in invalid state.
   bool ParseBuffer(const uint8_t* buffer, size_t size);
 
-  // Find an extension based on the type field of the parameter.
-  // If found, length field would be validated, the offset field will be set
-  // and true returned,
-  // otherwise the parameter will be unchanged and false is returned.
-  bool FindExtension(ExtensionType type,
-                     uint8_t length,
-                     uint16_t* offset) const;
+  // Find an extension |type|.
+  // Returns view of the raw extension or empty view on failure.
+  rtc::ArrayView<const uint8_t> FindExtension(ExtensionType type) const;
 
-  // Find or allocate an extension, based on the type field of the parameter.
-  // If found, the length field be checked against what is already registered
-  // and the offset field will be set, then true is returned. If allocated, the
-  // length field will be used for allocation and the offset update to indicate
-  // position, the true is returned.
-  // If not found and allocations fails, false is returned and parameter remains
-  // unchanged.
-  bool AllocateExtension(ExtensionType type, uint8_t length, uint16_t* offset);
+  // Find or allocate an extension |type|. Returns view of size |length|
+  // to write raw extension to or an empty view on failure.
+  rtc::ArrayView<uint8_t> AllocateExtension(ExtensionType type, size_t length);
 
   uint8_t* WriteAt(size_t offset);
   void WriteAt(size_t offset, uint8_t byte);
 
   // Header.
   bool marker_;
   uint8_t payload_type_;
   uint8_t padding_size_;
@@ -158,48 +165,42 @@ class Packet {
 
   ExtensionInfo extension_entries_[kMaxExtensionHeaders];
   uint16_t extensions_size_ = 0;  // Unaligned.
   rtc::CopyOnWriteBuffer buffer_;
 };
 
 template <typename Extension>
 bool Packet::HasExtension() const {
-  uint16_t offset = 0;
-  return FindExtension(Extension::kId, Extension::kValueSizeBytes, &offset);
+  return !FindExtension(Extension::kId).empty();
 }
 
 template <typename Extension, typename... Values>
 bool Packet::GetExtension(Values... values) const {
-  uint16_t offset = 0;
-  if (!FindExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+  auto raw = FindExtension(Extension::kId);
+  if (raw.empty())
     return false;
-  return Extension::Parse(data() + offset, values...);
+  return Extension::Parse(raw, values...);
 }
 
 template <typename Extension, typename... Values>
 bool Packet::SetExtension(Values... values) {
-  uint16_t offset = 0;
-  if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+  const size_t value_size = Extension::ValueSize(values...);
+  if (value_size == 0 || value_size > 16)
     return false;
-  return Extension::Write(WriteAt(offset), values...);
-}
-
-template <typename Extension, typename... Values>
-bool Packet::SetExtensionWithLength(size_t length, Values... values) {
-  uint16_t offset = 0;
-  if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes + length, &offset))
+  auto buffer = AllocateExtension(Extension::kId, value_size);
+  if (buffer.empty())
     return false;
-  return Extension::Write(WriteAt(offset), values...);
+  return Extension::Write(buffer.data(), values...);
 }
 
 template <typename Extension>
 bool Packet::ReserveExtension() {
-  uint16_t offset = 0;
-  if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+  auto buffer = AllocateExtension(Extension::kId, Extension::kValueSizeBytes);
+  if (buffer.empty())
     return false;
-  memset(WriteAt(offset), 0, Extension::kValueSizeBytes);
+  memset(buffer.data(), 0, Extension::kValueSizeBytes);
   return true;
 }
 }  // namespace rtp
 }  // namespace webrtc
 
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -18,60 +18,74 @@
 
 using testing::ElementsAreArray;
 using testing::make_tuple;
 
 namespace webrtc {
 namespace {
 constexpr int8_t kPayloadType = 100;
 constexpr uint32_t kSsrc = 0x12345678;
-constexpr uint16_t kSeqNum = 88;
+constexpr uint16_t kSeqNum = 0x1234;
+constexpr uint8_t kSeqNumFirstByte = kSeqNum >> 8;
+constexpr uint8_t kSeqNumSecondByte = kSeqNum & 0xff;
 constexpr uint32_t kTimestamp = 0x65431278;
 constexpr uint8_t kTransmissionOffsetExtensionId = 1;
 constexpr uint8_t kAudioLevelExtensionId = 9;
+constexpr uint8_t kRtpStreamIdExtensionId = 0xa;
 constexpr int32_t kTimeOffset = 0x56ce;
 constexpr bool kVoiceActive = true;
 constexpr uint8_t kAudioLevel = 0x5a;
+constexpr char kStreamId[] = "streamid";
 constexpr size_t kMaxPaddingSize = 224u;
 // clang-format off
 constexpr uint8_t kMinimumPacket[] = {
-    0x80, kPayloadType, 0x00, kSeqNum,
+    0x80, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78};
+
 constexpr uint8_t kPacketWithTO[] = {
-    0x90, kPayloadType, 0x00, kSeqNum,
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78,
     0xbe, 0xde, 0x00, 0x01,
     0x12, 0x00, 0x56, 0xce};
 
 constexpr uint8_t kPacketWithTOAndAL[] = {
-    0x90, kPayloadType, 0x00, kSeqNum,
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78,
     0xbe, 0xde, 0x00, 0x02,
     0x12, 0x00, 0x56, 0xce,
     0x90, 0x80|kAudioLevel, 0x00, 0x00};
 
+constexpr uint8_t kPacketWithRsid[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x03,
+    0xa7, 's',  't',  'r',
+    'e',  'a',  'm',  'i',
+    'd' , 0x00, 0x00, 0x00};
+
 constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465};
 constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'};
 constexpr uint8_t kPacketPaddingSize = 8;
 constexpr uint8_t kPacket[] = {
-    0xb2, kPayloadType, 0x00, kSeqNum,
+    0xb2, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78,
     0x34, 0x56, 0x78, 0x90,
     0x32, 0x43, 0x54, 0x65,
     0xbe, 0xde, 0x00, 0x01,
     0x12, 0x00, 0x56, 0xce,
     'p', 'a', 'y', 'l', 'o', 'a', 'd',
     'p', 'a', 'd', 'd', 'i', 'n', 'g', kPacketPaddingSize};
 
 constexpr uint8_t kPacketWithInvalidExtension[] = {
-    0x90, kPayloadType, 0x00, kSeqNum,
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,  // kTimestamp.
     0x12, 0x34, 0x56, 0x78,  // kSSrc.
     0xbe, 0xde, 0x00, 0x02,  // Extension block of size 2 x 32bit words.
     (kTransmissionOffsetExtensionId << 4) | 6,  // (6+1)-byte extension, but
            'e',  'x',  't',                     // Transmission Offset
      'd',  'a',  't',  'a',                     // expected to be 3-bytes.
      'p',  'a',  'y',  'l',  'o',  'a',  'd'
 };
@@ -111,26 +125,100 @@ TEST(RtpPacketTest, CreateWith2Extension
   packet.SetTimestamp(kTimestamp);
   packet.SetSsrc(kSsrc);
   packet.SetExtension<TransmissionOffset>(kTimeOffset);
   packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel);
   EXPECT_THAT(kPacketWithTOAndAL,
               ElementsAreArray(packet.data(), packet.size()));
 }
 
+TEST(RtpPacketTest, CreateWithDynamicSizedExtensions) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetExtension<RtpStreamId>(kStreamId);
+  EXPECT_THAT(kPacketWithRsid, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, TryToCreateWithEmptyRsid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpStreamId>(""));
+}
+
+TEST(RtpPacketTest, TryToCreateWithLongRsid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  constexpr char kLongStreamId[] = "LoooooooooongRsid";
+  ASSERT_EQ(strlen(kLongStreamId), 17u);
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpStreamId>(kLongStreamId));
+}
+
+TEST(RtpPacketTest, CreateWithExtensionsWithoutManager) {
+  RtpPacketToSend packet(nullptr);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+
+  auto raw = packet.AllocateRawExtension(kTransmissionOffsetExtensionId,
+                                         TransmissionOffset::kValueSizeBytes);
+  EXPECT_EQ(raw.size(), TransmissionOffset::kValueSizeBytes);
+  TransmissionOffset::Write(raw.data(), kTimeOffset);
+
+  raw = packet.AllocateRawExtension(kAudioLevelExtensionId,
+                                    AudioLevel::kValueSizeBytes);
+  EXPECT_EQ(raw.size(), AudioLevel::kValueSizeBytes);
+  AudioLevel::Write(raw.data(), kVoiceActive, kAudioLevel);
+
+  EXPECT_THAT(kPacketWithTOAndAL,
+              ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWithMaxSizeHeaderExtension) {
+  const size_t kMaxExtensionSize = 16;
+  const int kId = 1;
+  const uint8_t kValue[16] = "123456789abcdef";
+
+  // Write packet with a custom extension.
+  RtpPacketToSend packet(nullptr);
+  packet.SetRawExtension(kId, kValue);
+  // Using different size for same id is not allowed.
+  EXPECT_TRUE(packet.AllocateRawExtension(kId, kMaxExtensionSize - 1).empty());
+
+  packet.SetPayloadSize(42);
+  // Rewriting allocated extension is allowed.
+  EXPECT_EQ(packet.AllocateRawExtension(kId, kMaxExtensionSize).size(),
+            kMaxExtensionSize);
+  // Adding another extension after payload is set is not allowed.
+  EXPECT_TRUE(packet.AllocateRawExtension(kId + 1, kMaxExtensionSize).empty());
+
+  // Read packet with the custom extension.
+  RtpPacketReceived parsed;
+  EXPECT_TRUE(parsed.Parse(packet.Buffer()));
+  auto read_raw = parsed.GetRawExtension(kId);
+  EXPECT_THAT(read_raw, ElementsAreArray(kValue, kMaxExtensionSize));
+}
+
 TEST(RtpPacketTest, SetReservedExtensionsAfterPayload) {
   const size_t kPayloadSize = 4;
   RtpPacketToSend::ExtensionManager extensions;
   extensions.Register(kRtpExtensionTransmissionTimeOffset,
                       kTransmissionOffsetExtensionId);
   extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
   RtpPacketToSend packet(&extensions);
 
   EXPECT_TRUE(packet.ReserveExtension<TransmissionOffset>());
-  packet.AllocatePayload(kPayloadSize);
+  packet.SetPayloadSize(kPayloadSize);
   // Can't set extension after payload.
   EXPECT_FALSE(packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel));
   // Unless reserved.
   EXPECT_TRUE(packet.SetExtension<TransmissionOffset>(kTimeOffset));
 }
 
 TEST(RtpPacketTest, CreatePurePadding) {
   const size_t kPaddingSize = kMaxPaddingSize - 1;
@@ -149,17 +237,17 @@ TEST(RtpPacketTest, CreatePurePadding) {
 
 TEST(RtpPacketTest, CreateUnalignedPadding) {
   const size_t kPayloadSize = 3;  // Make padding start at unaligned address.
   RtpPacketToSend packet(nullptr, 12 + kPayloadSize + kMaxPaddingSize);
   packet.SetPayloadType(kPayloadType);
   packet.SetSequenceNumber(kSeqNum);
   packet.SetTimestamp(kTimestamp);
   packet.SetSsrc(kSsrc);
-  packet.AllocatePayload(kPayloadSize);
+  packet.SetPayloadSize(kPayloadSize);
   Random r(0x123456789);
 
   EXPECT_LT(packet.size(), packet.capacity());
   EXPECT_TRUE(packet.SetPadding(kMaxPaddingSize, &r));
   EXPECT_EQ(packet.size(), packet.capacity());
 }
 
 TEST(RtpPacketTest, ParseMinimum) {
@@ -220,17 +308,17 @@ TEST(RtpPacketTest, ParseWithInvalidSize
 
   // But shouldn't prevent reading payload.
   EXPECT_THAT(packet.payload(), ElementsAreArray(kPayload));
 }
 
 TEST(RtpPacketTest, ParseWithOverSizedExtension) {
   // clang-format off
   const uint8_t bad_packet[] = {
-      0x90, kPayloadType, 0x00, kSeqNum,
+      0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
       0x65, 0x43, 0x12, 0x78,  // kTimestamp.
       0x12, 0x34, 0x56, 0x78,  // kSsrc.
       0xbe, 0xde, 0x00, 0x01,  // Extension of size 1x32bit word.
       0x00,  // Add a byte of padding.
             0x12,  // Extension id 1 size (2+1).
                   0xda, 0x1a  // Only 2 bytes of extension payload.
   };
   // clang-format on
@@ -295,9 +383,82 @@ TEST(RtpPacketTest, ParseWithExtensionDe
   EXPECT_FALSE(packet.GetExtension<TransmissionOffset>(&time_offset));
   packet.IdentifyExtensions(extensions);
   EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
   EXPECT_EQ(kTimeOffset, time_offset);
   EXPECT_EQ(0u, packet.payload_size());
   EXPECT_EQ(0u, packet.padding_size());
 }
 
+TEST(RtpPacketTest, ParseWithoutExtensionManager) {
+  RtpPacketReceived packet;
+  EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
+
+  EXPECT_FALSE(packet.HasRawExtension(kAudioLevelExtensionId));
+  EXPECT_TRUE(packet.GetRawExtension(kAudioLevelExtensionId).empty());
+
+  EXPECT_TRUE(packet.HasRawExtension(kTransmissionOffsetExtensionId));
+
+  int32_t time_offset = 0;
+  auto raw_extension = packet.GetRawExtension(kTransmissionOffsetExtensionId);
+  EXPECT_EQ(raw_extension.size(), TransmissionOffset::kValueSizeBytes);
+  EXPECT_TRUE(TransmissionOffset::Parse(raw_extension, &time_offset));
+
+  EXPECT_EQ(time_offset, kTimeOffset);
+}
+
+TEST(RtpPacketTest, ParseDynamicSizeExtension) {
+  // clang-format off
+  const uint8_t kPacket1[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // Timestamp.
+    0x12, 0x34, 0x56, 0x78,  // Ssrc.
+    0xbe, 0xde, 0x00, 0x02,  // Extensions block of size 2x32bit words.
+    0x21, 'H', 'D',          // Extension with id = 2, size = (1+1).
+    0x12, 'r', 't', 'x',     // Extension with id = 1, size = (2+1).
+    0x00};  // Extension padding.
+  const uint8_t kPacket2[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // Timestamp.
+    0x12, 0x34, 0x56, 0x79,  // Ssrc.
+    0xbe, 0xde, 0x00, 0x01,  // Extensions block of size 1x32bit words.
+    0x11, 'H', 'D',          // Extension with id = 1, size = (1+1).
+    0x00};  // Extension padding.
+  // clang-format on
+  RtpPacketReceived::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(1);
+  extensions.Register<RepairedRtpStreamId>(2);
+  RtpPacketReceived packet(&extensions);
+  ASSERT_TRUE(packet.Parse(kPacket1, sizeof(kPacket1)));
+
+  std::string rsid;
+  EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
+  EXPECT_EQ(rsid, "rtx");
+
+  std::string repaired_rsid;
+  EXPECT_TRUE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
+  EXPECT_EQ(repaired_rsid, "HD");
+
+  // Parse another packet with RtpStreamId extension of different size.
+  ASSERT_TRUE(packet.Parse(kPacket2, sizeof(kPacket2)));
+  EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
+  EXPECT_EQ(rsid, "HD");
+  EXPECT_FALSE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
+}
+
+TEST(RtpPacketTest, RawExtensionFunctionsAcceptZeroIdAndReturnFalse) {
+  RtpPacketReceived::ExtensionManager extensions;
+  RtpPacketReceived packet(&extensions);
+  // Use ExtensionManager to set kInvalidId to 0 to demonstrate natural way for
+  // using zero value as a parameter to Packet::*RawExtension functions.
+  const int kInvalidId = extensions.GetId(TransmissionOffset::kId);
+  ASSERT_EQ(kInvalidId, 0);
+
+  ASSERT_TRUE(packet.Parse(kPacket, sizeof(kPacket)));
+
+  EXPECT_FALSE(packet.HasRawExtension(kInvalidId));
+  EXPECT_THAT(packet.GetRawExtension(kInvalidId), IsEmpty());
+  const uint8_t kExtension[] = {'e', 'x', 't'};
+  EXPECT_FALSE(packet.SetRawExtension(kInvalidId, kExtension));
+  EXPECT_THAT(packet.AllocateRawExtension(kInvalidId, 3), IsEmpty());
+}
+
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc
@@ -64,18 +64,17 @@ RtpReceiverImpl::RtpReceiverImpl(
       cb_rtp_feedback_(incoming_messages_callback),
       last_receive_time_(0),
       last_received_payload_length_(0),
       ssrc_(0),
       num_csrcs_(0),
       current_remote_csrc_(),
       last_received_timestamp_(0),
       last_received_frame_time_ms_(-1),
-      last_received_sequence_number_(0),
-      rid_(NULL) {
+      last_received_sequence_number_(0) {
   assert(incoming_messages_callback);
 
   memset(current_remote_csrc_, 0, sizeof(current_remote_csrc_));
 }
 
 RtpReceiverImpl::~RtpReceiverImpl() {
   for (int i = 0; i < num_csrcs_; ++i) {
     cb_rtp_feedback_->OnIncomingCSRCChanged(current_remote_csrc_[i], false);
@@ -124,22 +123,22 @@ int32_t RtpReceiverImpl::CSRCs(uint32_t 
   assert(num_csrcs_ <= kRtpCsrcSize);
 
   if (num_csrcs_ > 0) {
     memcpy(array_of_csrcs, current_remote_csrc_, sizeof(uint32_t)*num_csrcs_);
   }
   return num_csrcs_;
 }
 
-void RtpReceiverImpl::GetRID(char rid[256]) const {
+void RtpReceiverImpl::GetRID(char rtp_stream_id[256]) const {
   rtc::CritScope lock(&critical_section_rtp_receiver_);
-  if (rid_) {
-    strncpy(rid, rid_, 256);
+  if (!rtp_stream_id_.empty()) {
+    strncpy(rtp_stream_id, rtp_stream_id_.data(), 256);
   } else {
-    rid[0] = '\0';
+    rtp_stream_id[0] = '\0';
   }
 }
 
 int32_t RtpReceiverImpl::Energy(
     uint8_t array_of_energy[kRtpCsrcSize]) const {
   return rtp_media_receiver_->Energy(array_of_energy);
 }
 
@@ -194,23 +193,21 @@ bool RtpReceiverImpl::IncomingRtpPacket(
 
   {
     rtc::CritScope lock(&critical_section_rtp_receiver_);
 
     last_receive_time_ = clock_->TimeInMilliseconds();
     last_received_payload_length_ = payload_data_length;
 
     // RID rarely if ever changes
-    if (rtp_header.extension.hasRID &&
-        (!rid_ || strcmp(rtp_header.extension.rid.get(), rid_) != 0)) {
-      delete [] rid_;
-      rid_ = new char[strlen(rtp_header.extension.rid.get())+1];
-      strcpy(rid_, rtp_header.extension.rid.get());
-      LOG(LS_INFO) << "Received new RID value: " << rid_;
-  }
+    if (!rtp_header.extension.rtpStreamId.empty() &&
+        (rtp_header.extension.rtpStreamId != rtp_stream_id_)) {
+      rtp_stream_id_ = rtp_header.extension.rtpStreamId;
+      LOG(LS_INFO) << "Received new RID value: " << rtp_stream_id_.data();
+    }
     if (in_order) {
       if (last_received_timestamp_ != rtp_header.timestamp) {
         last_received_timestamp_ = rtp_header.timestamp;
         last_received_frame_time_ms_ = clock_->TimeInMilliseconds();
       }
       last_received_sequence_number_ = rtp_header.sequenceNumber;
     }
   }
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h
@@ -47,17 +47,17 @@ class RtpReceiverImpl : public RtpReceiv
   // Returns the last received timestamp.
   bool Timestamp(uint32_t* timestamp) const override;
   bool LastReceivedTimeMs(int64_t* receive_time_ms) const override;
 
   uint32_t SSRC() const override;
 
   int32_t CSRCs(uint32_t array_of_csrc[kRtpCsrcSize]) const override;
 
-  void GetRID(char rid[256]) const override;
+  void GetRID(char rtp_stream_id[256]) const override;
 
   int32_t Energy(uint8_t array_of_energy[kRtpCsrcSize]) const override;
 
   TelephoneEventHandler* GetTelephoneEventHandler() override;
 
  private:
   bool HaveReceivedFrame() const;
 
@@ -81,12 +81,12 @@ class RtpReceiverImpl : public RtpReceiv
   // SSRCs.
   uint32_t ssrc_;
   uint8_t num_csrcs_;
   uint32_t current_remote_csrc_[kRtpCsrcSize];
 
   uint32_t last_received_timestamp_;
   int64_t last_received_frame_time_ms_;
   uint16_t last_received_sequence_number_;
-  char *rid_;
+  StreamId rtp_stream_id_;
 };
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -25,30 +25,44 @@
 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 #include "webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h"
 #include "webrtc/modules/rtp_rtcp/source/time_util.h"
 #include "webrtc/system_wrappers/include/field_trial.h"
+#include "webrtc/modules/rtp_rtcp/source/ssrc_database.h"
 
 namespace webrtc {
 
 namespace {
 // Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
 constexpr size_t kMaxPaddingLength = 224;
 constexpr int kSendSideDelayWindowMs = 1000;
 constexpr size_t kRtpHeaderLength = 12;
 constexpr uint16_t kMaxInitRtpSeqNumber = 32767;  // 2^15 -1.
 constexpr uint32_t kTimestampTicksPerMs = 90;
 constexpr int kBitrateStatisticsWindowMs = 1000;
 
 constexpr size_t kMinFlexfecPacketsToStoreForPacing = 50;
 
+template <typename Extension>
+constexpr RtpExtensionSize CreateExtensionSize() {
+  return {Extension::kId, Extension::kValueSizeBytes};
+}
+
+// Size info for header extensions that might be used in padding or FEC packets.
+constexpr RtpExtensionSize kExtensionSizes[] = {
+    CreateExtensionSize<AbsoluteSendTime>(),
+    CreateExtensionSize<TransmissionOffset>(),
+    CreateExtensionSize<TransportSequenceNumber>(),
+    CreateExtensionSize<PlayoutDelayLimits>(),
+};
+
 const char* FrameTypeToString(FrameType frame_type) {
   switch (frame_type) {
     case kEmptyFrame:
       return "empty";
     case kAudioFrameSpeech: return "audio_speech";
     case kAudioFrameCN: return "audio_cn";
     case kVideoFrameKey: return "video_key";
     case kVideoFrameDelta: return "video_delta";
@@ -92,17 +106,16 @@ RTPSender::RTPSender(
       transport_feedback_observer_(transport_feedback_observer),
       last_capture_time_ms_sent_(0),
       transport_(transport),
       sending_media_(true),                   // Default to sending media.
       max_packet_size_(IP_PACKET_SIZE - 28),  // Default is IP-v4/UDP.
       payload_type_(-1),
       payload_type_map_(),
       rtp_header_extension_map_(),
-      rid_{0},
       packet_history_(clock),
       flexfec_packet_history_(clock),
       // Statistics
       rtp_stats_callback_(nullptr),
       total_bitrate_sent_(kBitrateStatisticsWindowMs,
                           RateStatistics::kBpsScale),
       nack_bitrate_sent_(kBitrateStatisticsWindowMs, RateStatistics::kBpsScale),
       frame_count_observer_(frame_count_observer),
@@ -163,16 +176,20 @@ RTPSender::~RTPSender() {
   while (!payload_type_map_.empty()) {
     std::map<int8_t, RtpUtility::Payload*>::iterator it =
         payload_type_map_.begin();
     delete it->second;
     payload_type_map_.erase(it);
   }
 }
 
+rtc::ArrayView<const RtpExtensionSize> RTPSender::FecExtensionSizes() {
+  return rtc::MakeArrayView(kExtensionSizes, arraysize(kExtensionSizes));
+}
+
 uint16_t RTPSender::ActualSendBitrateKbit() const {
   rtc::CritScope cs(&statistics_crit_);
   return static_cast<uint16_t>(
       total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0) /
       1000);
 }
 
 uint32_t RTPSender::VideoBitrateSent() const {
@@ -191,46 +208,30 @@ uint32_t RTPSender::FecOverheadRate() co
 
 uint32_t RTPSender::NackOverheadRate() const {
   rtc::CritScope cs(&statistics_crit_);
   return nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
 }
 
 int32_t RTPSender::SetRID(const char* rid) {
   rtc::CritScope lock(&send_critsect_);
-  const size_t len = rid ? strlen(rid) : 0;
-  if (!len || len >= sizeof(rid_)) {
-    rid_[0] = '\0';
-  } else {
-    memmove(&rid_[0], rid, len + 1);
+  const size_t len = (rid && rid[0]) ? strlen(rid) : 0;
+  if (len) {
+    rtpStreamId.Set(rid, len);
   }
   return 0;
 }
 
 int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type,
                                               uint8_t id) {
   rtc::CritScope lock(&send_critsect_);
-  switch (type) {
-    case kRtpExtensionVideoRotation:
-    case kRtpExtensionPlayoutDelay:
-    case kRtpExtensionTransmissionTimeOffset:
-    case kRtpExtensionAbsoluteSendTime:
-    case kRtpExtensionAudioLevel:
-    case kRtpExtensionTransportSequenceNumber:
-    case kRtpExtensionRtpStreamId:
-      return rtp_header_extension_map_.Register(type, id);
-    case kRtpExtensionNone:
-    case kRtpExtensionNumberOfExtensions:
-      LOG(LS_ERROR) << "Invalid RTP extension type for registration";
-      return -1;
-  }
-  return -1;
+  return rtp_header_extension_map_.RegisterByType(id, type) ? 0 : -1;
 }
 
-bool RTPSender::IsRtpHeaderExtensionRegistered(RTPExtensionType type) {
+bool RTPSender::IsRtpHeaderExtensionRegistered(RTPExtensionType type) const {
   rtc::CritScope lock(&send_critsect_);
   return rtp_header_extension_map_.IsRegistered(type);
 }
 
 int32_t RTPSender::DeregisterRtpHeaderExtension(RTPExtensionType type) {
   rtc::CritScope lock(&send_critsect_);
   return rtp_header_extension_map_.Deregister(type);
 }
@@ -445,17 +446,17 @@ bool RTPSender::SendOutgoingData(FrameTy
     if (rtp_header) {
       playout_delay_oracle_.UpdateRequest(ssrc, rtp_header->playout_delay,
                                           sequence_number);
     }
 
     result = video_->SendVideo(video_type, frame_type, payload_type,
                                rtp_timestamp, capture_time_ms, payload_data,
                                payload_size, fragmentation, rtp_header,
-                               &rid_[0]);
+                               &rtpStreamId);
   }
 
   rtc::CritScope cs(&statistics_crit_);
   // Note: This is currently only counting for video.
   if (frame_type == kVideoFrameKey) {
     ++frame_counts_.key_frames;
   } else if (frame_type == kVideoFrameDelta) {
     ++frame_counts_.delta_frames;
@@ -554,17 +555,18 @@ size_t RTPSender::SendPadData(size_t byt
     padding_packet->SetSequenceNumber(sequence_number);
     padding_packet->SetTimestamp(timestamp);
     padding_packet->SetSsrc(ssrc);
 
     if (capture_time_ms > 0) {
       padding_packet->SetExtension<TransmissionOffset>(
           (now_ms - capture_time_ms) * kTimestampTicksPerMs);
     }
-    padding_packet->SetExtension<AbsoluteSendTime>(now_ms);
+    padding_packet->SetExtension<AbsoluteSendTime>(
+        AbsoluteSendTime::MsTo24Bits(now_ms));
     PacketOptions options;
     bool has_transport_seq_num =
       UpdateTransportSequenceNumber(padding_packet.get(), &options.packet_id);
     padding_packet->SetPadding(padding_bytes_in_packet, &random_);
 
     if (has_transport_seq_num) {
       AddPacketToTransportFeedback(options.packet_id, *padding_packet,
                                    probe_cluster_id);
@@ -738,17 +740,18 @@ bool RTPSender::PrepareAndSendPacket(std
       return false;
     packet_to_send = packet_rtx.get();
   }
 
   int64_t now_ms = clock_->TimeInMilliseconds();
   int64_t diff_ms = now_ms - capture_time_ms;
   packet_to_send->SetExtension<TransmissionOffset>(kTimestampTicksPerMs *
                                                    diff_ms);
-  packet_to_send->SetExtension<AbsoluteSendTime>(now_ms);
+  packet_to_send->SetExtension<AbsoluteSendTime>(
+      AbsoluteSendTime::MsTo24Bits(now_ms));
 
   PacketOptions options;
   if (UpdateTransportSequenceNumber(packet_to_send, &options.packet_id)) {
     AddPacketToTransportFeedback(options.packet_id, *packet_to_send,
                                  probe_cluster_id);
   }
 
   if (!is_retransmit && !send_over_rtx) {
@@ -827,17 +830,17 @@ bool RTPSender::SendToNetwork(std::uniqu
 
   // |capture_time_ms| <= 0 is considered invalid.
   // TODO(holmer): This should be changed all over Video Engine so that negative
   // time is consider invalid, while 0 is considered a valid time.
   if (packet->capture_time_ms() > 0) {
     packet->SetExtension<TransmissionOffset>(
         kTimestampTicksPerMs * (now_ms - packet->capture_time_ms()));
   }
-  packet->SetExtension<AbsoluteSendTime>(now_ms);
+  packet->SetExtension<AbsoluteSendTime>(AbsoluteSendTime::MsTo24Bits(now_ms));
 
   if (video_) {
     BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoTotBitrate_kbps", now_ms,
                                     ActualSendBitrateKbit(), packet->Ssrc());
     BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoFecBitrate_kbps", now_ms,
                                     FecOverheadRate() / 1000, packet->Ssrc());
     BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoNackBitrate_kbps", now_ms,
                                     NackOverheadRate() / 1000, packet->Ssrc());
@@ -965,17 +968,18 @@ void RTPSender::ProcessBitrate() {
   bitrate_callback_->Notify(total_bitrate_sent_.Rate(now_ms).value_or(0),
                             nack_bitrate_sent_.Rate(now_ms).value_or(0), ssrc);
 }
 
 size_t RTPSender::RtpHeaderLength() const {
   rtc::CritScope lock(&send_critsect_);
   size_t rtp_header_length = kRtpHeaderLength;
   rtp_header_length += sizeof(uint32_t) * csrcs_.size();
-  rtp_header_length += rtp_header_extension_map_.GetTotalLengthInBytes();
+  rtp_header_length +=
+      rtp_header_extension_map_.GetTotalLengthInBytes(kExtensionSizes);
   return rtp_header_length;
 }
 
 uint16_t RTPSender::AllocateSequenceNumber(uint16_t packets_to_send) {
   rtc::CritScope lock(&send_critsect_);
   uint16_t first_allocated_sequence_number = sequence_number_;
   sequence_number_ += packets_to_send;
   return first_allocated_sequence_number;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h
@@ -12,41 +12,42 @@
 #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
 
 #include <map>
 #include <memory>
 #include <utility>
 #include <vector>
 
 #include "webrtc/api/call/transport.h"
+#include "webrtc/base/array_view.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/base/criticalsection.h"
 #include "webrtc/base/deprecation.h"
 #include "webrtc/base/optional.h"
 #include "webrtc/base/random.h"
 #include "webrtc/base/rate_statistics.h"
 #include "webrtc/base/thread_annotations.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/rtp_rtcp/include/flexfec_sender.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h"
-#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
-#include "webrtc/modules/rtp_rtcp/source/ssrc_database.h"
 
 namespace webrtc {
 
 class OverheadObserver;
 class RateLimiter;
 class RtcEventLog;
 class RtpPacketToSend;
 class RTPSenderAudio;
 class RTPSenderVideo;
+class SSRCDatabase;
 
 class RTPSender {
  public:
   RTPSender(bool audio,
             Clock* clock,
             Transport* transport,
             RtpPacketSender* paced_sender,
             // TODO(brandtr): Remove |flexfec_sender| when that is hooked up
@@ -117,17 +118,17 @@ class RTPSender {
                         const RTPFragmentationHeader* fragmentation,
                         const RTPVideoHeader* rtp_header,
                         uint32_t* transport_frame_id_out);
 
   int32_t SetRID(const char* rid);
 
   // RTP header extension
   int32_t RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id);
-  bool IsRtpHeaderExtensionRegistered(RTPExtensionType type);
+  bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) const;
   int32_t DeregisterRtpHeaderExtension(RTPExtensionType type);
 
   bool TimeToSendPacket(uint32_t ssrc,
                         uint16_t sequence_number,
                         int64_t capture_time_ms,
                         bool retransmission,
                         int probe_cluster_id);
   size_t TimeToSendPadding(size_t bytes, int probe_cluster_id);
@@ -151,24 +152,28 @@ class RTPSender {
   void SetRtxStatus(int mode);
   int RtxStatus() const;
 
   uint32_t RtxSsrc() const;
   void SetRtxSsrc(uint32_t ssrc);
 
   void SetRtxPayloadType(int payload_type, int associated_payload_type);
 
+  // Size info for header extensions used by FEC packets.
+  static rtc::ArrayView<const RtpExtensionSize> FecExtensionSizes();
+
   // Create empty packet, fills ssrc, csrcs and reserve place for header
   // extensions RtpSender updates before sending.
   std::unique_ptr<RtpPacketToSend> AllocatePacket() const;
   // Allocate sequence number for provided packet.
   // Save packet's fields to generate padding that doesn't break media stream.
   // Return false if sending was turned off.
   bool AssignSequenceNumber(RtpPacketToSend* packet);
 
+  // Used for padding and FEC packets only.
   size_t RtpHeaderLength() const;
   uint16_t AllocateSequenceNumber(uint16_t packets_to_send);
   // Including RTP headers.
   size_t MaxRtpPacketSize() const;
 
   uint32_t SSRC() const;
 
   rtc::Optional<uint32_t> FlexfecSsrc() const;
@@ -275,17 +280,17 @@ class RTPSender {
 
   size_t max_packet_size_;
 
   int8_t payload_type_ GUARDED_BY(send_critsect_);
   std::map<int8_t, RtpUtility::Payload*> payload_type_map_;
 
   RtpHeaderExtensionMap rtp_header_extension_map_ GUARDED_BY(send_critsect_);
 
-  char rid_[kRIDSize + 1] GUARDED_BY(send_critsect_);
+  StreamId rtpStreamId GUARDED_BY(send_critsect_);
 
   // Tracks the current request for playout delay limits from application
   // and decides whether the current RTP frame should include the playout
   // delay extension on header.
   PlayoutDelayOracle playout_delay_oracle_;
 
   RtpPacketHistory packet_history_;
   // TODO(brandtr): Remove |flexfec_packet_history_| when the FlexfecSender
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -799,18 +799,20 @@ TEST_F(RtpSenderTestWithoutPacer, SendGe
 }
 
 TEST_F(RtpSenderTest, SendFlexfecPackets) {
   constexpr int kMediaPayloadType = 127;
   constexpr int kFlexfecPayloadType = 118;
   constexpr uint32_t kMediaSsrc = 1234;
   constexpr uint32_t kFlexfecSsrc = 5678;
   const std::vector<RtpExtension> kNoRtpExtensions;
+  const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
   FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                               kNoRtpExtensions, &fake_clock_);
+                               kNoRtpExtensions, kNoRtpExtensionSizes,
+                               &fake_clock_);
 
   // Reset |rtp_sender_| to use FlexFEC.
   rtp_sender_.reset(new RTPSender(
       false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
       &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
       &mock_rtc_event_log_, &send_packet_observer_,
       &retransmission_rate_limiter_, nullptr));
   rtp_sender_->SetSSRC(kMediaSsrc);
@@ -853,18 +855,20 @@ TEST_F(RtpSenderTest, SendFlexfecPackets
 }
 
 TEST_F(RtpSenderTestWithoutPacer, SendFlexfecPackets) {
   constexpr int kMediaPayloadType = 127;
   constexpr int kFlexfecPayloadType = 118;
   constexpr uint32_t kMediaSsrc = 1234;
   constexpr uint32_t kFlexfecSsrc = 5678;
   const std::vector<RtpExtension> kNoRtpExtensions;
+  const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
   FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                               kNoRtpExtensions, &fake_clock_);
+                               kNoRtpExtensions, kNoRtpExtensionSizes,
+                               &fake_clock_);
 
   // Reset |rtp_sender_| to use FlexFEC.
   rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr,
                                   &flexfec_sender, &seq_num_allocator_, nullptr,
                                   nullptr, nullptr, nullptr,
                                   &mock_rtc_event_log_, &send_packet_observer_,
                                   &retransmission_rate_limiter_, nullptr));
   rtp_sender_->SetSSRC(kMediaSsrc);
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -286,17 +286,17 @@ bool RTPSenderVideo::SendVideo(RtpVideoC
                                FrameType frame_type,
                                int8_t payload_type,
                                uint32_t rtp_timestamp,
                                int64_t capture_time_ms,
                                const uint8_t* payload_data,
                                size_t payload_size,
                                const RTPFragmentationHeader* fragmentation,
                                const RTPVideoHeader* video_header,
-                               const char* rid) {
+                               const StreamId* rtpStreamId) {
   if (payload_size == 0)
     return false;
 
   // Create header that will be reused in all packets.
   std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket();
   rtp_header->SetPayloadType(payload_type);
   rtp_header->SetTimestamp(rtp_timestamp);
   rtp_header->set_capture_time_ms(capture_time_ms);
@@ -320,21 +320,18 @@ bool RTPSenderVideo::SendVideo(RtpVideoC
       // Set rotation when key frame or when changed (to follow standard).
       // Or when different from 0 (to follow current receiver implementation).
       VideoRotation current_rotation = video_header->rotation;
       if (frame_type == kVideoFrameKey || current_rotation != last_rotation_ ||
           current_rotation != kVideoRotation_0)
         rtp_header->SetExtension<VideoOrientation>(current_rotation);
       last_rotation_ = current_rotation;
     }
-    if (rid && rid[0]) {
-      const size_t len = strlen(rid);
-      if (len) {
-        rtp_header->SetExtensionWithLength<StreamId>(len - 1, rid);
-      }
+    if (rtpStreamId && !rtpStreamId->empty()) {
+       rtp_header->SetExtension<RtpStreamId>(*rtpStreamId);
     }
 
     // FEC settings.
     const FecProtectionParams& fec_params =
         frame_type == kVideoFrameKey ? key_fec_params_ : delta_fec_params_;
     if (flexfec_enabled())
       flexfec_sender_->SetFecParameters(fec_params);
     if (ulpfec_enabled())
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h
@@ -56,17 +56,17 @@ class RTPSenderVideo {
                  FrameType frame_type,
                  int8_t payload_type,
                  uint32_t capture_timestamp,
                  int64_t capture_time_ms,
                  const uint8_t* payload_data,
                  size_t payload_size,
                  const RTPFragmentationHeader* fragmentation,
                  const RTPVideoHeader* video_header,
-                 const char* rid);
+                 const StreamId* rtpStreamId);
 
   void SetVideoCodecType(RtpVideoCodecTypes type);
 
   // ULPFEC.
   void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type);
   void GetUlpfecConfig(int* red_payload_type, int* ulpfec_payload_type) const;
 
   // FlexFEC/ULPFEC.
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
@@ -249,20 +249,16 @@ bool RtpHeaderParser::Parse(RTPHeader* h
   header->extension.voiceActivity = false;
   header->extension.audioLevel = 0;
 
   // May not be present in packet.
   header->extension.hasVideoRotation = false;
   header->extension.videoRotation = kVideoRotation_0;
 
   // May not be present in packet.
-  header->extension.hasRID = false;
-  header->extension.rid = NULL;
-
-  // May not be present in packet.
   header->extension.playout_delay.min_ms = -1;
   header->extension.playout_delay.max_ms = -1;
 
   if (X) {
     /* RTP header extension, RFC 3550.
      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -456,35 +452,22 @@ void RtpHeaderParser::ParseOneByteExtens
           int max_playout_delay = ((ptr[1] & 0xf) << 8) | ptr[2];
           header->extension.playout_delay.min_ms =
               min_playout_delay * kPlayoutDelayGranularityMs;
           header->extension.playout_delay.max_ms =
               max_playout_delay * kPlayoutDelayGranularityMs;
           break;
         }
         case kRtpExtensionRtpStreamId: {
-          //   0                   1                   2
-          //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
-          //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-          //  |  ID   | L=?   |UTF-8 RID value......          |...
-          //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-          // As per RFC 5285 section 4.2, len is the length of the header data
-          // - 1. E.G. a len of 0 indicates a header data length of 1
-          if ( &ptr[len + 1] > ptrRTPDataExtensionEnd ) {
-            LOG(LS_WARNING) << "Extension RtpStreamId data length " << (len + 1)
-              << " is longer than remaining input parse buffer "
-              << static_cast<size_t>(ptrRTPDataExtensionEnd - ptr);
-            return;
-          }
-
-          header->extension.rid.reset(new char[len + 2]);
-          memcpy(header->extension.rid.get(), ptr, len + 1);
-          header->extension.rid.get()[len + 1] = '\0';
-          header->extension.hasRID = true;
+          header->extension.rtpStreamId.Set(rtc::MakeArrayView(ptr, len + 1));
+          break;
+        }
+        case kRtpExtensionRepairedRtpStreamId: {
+          header->extension.repairedStreamId.Set(
+              rtc::MakeArrayView(ptr, len + 1));
           break;
         }
         default:
         case kRtpExtensionNone:
         case kRtpExtensionNumberOfExtensions: {
           RTC_NOTREACHED() << "Invalid extension type: " << type;
           return;
         }
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
@@ -143,42 +143,46 @@ TEST(RtpHeaderParser, ParseWithOverSized
 
   EXPECT_TRUE(parser.Parse(&header, &extensions));
 
   // Parse should ignore extension.
   EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
   EXPECT_EQ(sizeof(kPacket), header.headerLength);
 }
 
-TEST(RtpHeaderParser, ParseAll6Extensions) {
+TEST(RtpHeaderParser, ParseAll8Extensions) {
   const uint8_t kAudioLevel = 0x5a;
   // clang-format off
   const uint8_t kPacket[] = {
       0x90, kPayloadType, 0x00, kSeqNum,
       0x65, 0x43, 0x12, 0x78,  // kTimestamp.
       0x12, 0x34, 0x56, 0x78,  // kSsrc.
-      0xbe, 0xde, 0x00, 0x05,  // Extension of size 5x32bit word.
+      0xbe, 0xde, 0x00, 0x08,  // Extension of size 8x32bit words.
       0x40, 0x80|kAudioLevel,  // AudioLevel.
       0x22, 0x01, 0x56, 0xce,  // TransmissionOffset.
       0x62, 0x12, 0x34, 0x56,  // AbsoluteSendTime.
       0x81, 0xce, 0xab,        // TransportSequenceNumber.
       0xa0, 0x03,              // VideoRotation.
       0xb2, 0x12, 0x48, 0x76,  // PlayoutDelayLimits.
-      0x00,                    // Padding to 32bit boundary.
+      0xc2, 'r', 't', 'x',     // RtpStreamId
+      0xd5, 's', 't', 'r', 'e', 'a', 'm',  // RepairedRtpStreamId
+      0x00, 0x00,              // Padding to 32bit boundary.
   };
   // clang-format on
   ASSERT_EQ(sizeof(kPacket) % 4, 0u);
 
   RtpHeaderExtensionMap extensions;
   extensions.Register<TransmissionOffset>(2);
   extensions.Register<AudioLevel>(4);
   extensions.Register<AbsoluteSendTime>(6);
   extensions.Register<TransportSequenceNumber>(8);
   extensions.Register<VideoOrientation>(0xa);
   extensions.Register<PlayoutDelayLimits>(0xb);
+  extensions.Register<RtpStreamId>(0xc);
+  extensions.Register<RepairedRtpStreamId>(0xd);
   RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
   RTPHeader header;
 
   EXPECT_TRUE(parser.Parse(&header, &extensions));
 
   EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
   EXPECT_EQ(0x156ce, header.extension.transmissionTimeOffset);
 
@@ -194,16 +198,43 @@ TEST(RtpHeaderParser, ParseAll6Extension
 
   EXPECT_TRUE(header.extension.hasVideoRotation);
   EXPECT_EQ(kVideoRotation_270, header.extension.videoRotation);
 
   EXPECT_EQ(0x124 * PlayoutDelayLimits::kGranularityMs,
             header.extension.playout_delay.min_ms);
   EXPECT_EQ(0x876 * PlayoutDelayLimits::kGranularityMs,
             header.extension.playout_delay.max_ms);
+  EXPECT_EQ(header.extension.rtpStreamId, StreamId("rtx"));
+  EXPECT_EQ(header.extension.repairedStreamId, StreamId("stream"));
+}
+
+TEST(RtpHeaderParser, ParseMalformedRsidExtensions) {
+  // clang-format off
+  const uint8_t kPacket[] = {
+      0x90, kPayloadType, 0x00, kSeqNum,
+      0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+      0x12, 0x34, 0x56, 0x78,  // kSsrc.
+      0xbe, 0xde, 0x00, 0x03,  // Extension of size 3x32bit words.
+      0xc2, '\0', 't', 'x',    // empty RtpStreamId
+      0xd5, 's', 't', 'r', '\0', 'a', 'm',  // RepairedRtpStreamId
+      0x00,                    // Padding to 32bit boundary.
+  };
+  // clang-format on
+  ASSERT_EQ(sizeof(kPacket) % 4, 0u);
+
+  RtpHeaderExtensionMap extensions;
+  extensions.Register<RtpStreamId>(0xc);
+  extensions.Register<RepairedRtpStreamId>(0xd);
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, &extensions));
+  EXPECT_TRUE(header.extension.rtpStreamId.empty());
+  EXPECT_EQ(header.extension.repairedStreamId, StreamId("str"));
 }
 
 TEST(RtpHeaderParser, ParseWithCsrcsExtensionAndPadding) {
   const uint8_t kPacketPaddingSize = 8;
   const uint32_t kCsrcs[] = {0x34567890, 0x32435465};
   const size_t kPayloadSize = 7;
   // clang-format off
   const uint8_t kPacket[] = {
--- a/media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
+++ b/media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
@@ -9,40 +9,41 @@
  */
 
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_received.h"
 
 namespace webrtc {
 
-// We decide which header extensions to register by reading one byte
+// We decide which header extensions to register by reading two bytes
 // from the beginning of |data| and interpreting it as a bitmask over
-// the RTPExtensionType enum. This assert ensures one byte is enough.
-static_assert(kRtpExtensionNumberOfExtensions <= 8,
+// the RTPExtensionType enum. This assert ensures two bytes are enough.
+static_assert(kRtpExtensionNumberOfExtensions <= 16,
               "Insufficient bits read to configure all header extensions. Add "
               "an extra byte and update the switches.");
 
 void FuzzOneInput(const uint8_t* data, size_t size) {
-  if (size <= 1)
+  if (size <= 2)
     return;
 
-  // Don't use the configuration byte as part of the packet.
-  std::bitset<8> extensionMask(data[0]);
-  data++;
-  size--;
+  // Don't use the configuration bytes as part of the packet.
+  std::bitset<16> extensionMask(*reinterpret_cast<const uint16_t*>(data));
+  data += 2;
+  size -= 2;
 
   RtpPacketReceived::ExtensionManager extensions;
-  for (int i = 0; i < kRtpExtensionNumberOfExtensions; i++) {
+  // Skip i = 0 since it maps to ExtensionNone and extension id = 0 is invalid.
+  for (int i = 1; i < kRtpExtensionNumberOfExtensions; i++) {
     RTPExtensionType extension_type = static_cast<RTPExtensionType>(i);
     if (extensionMask[i] && extension_type != kRtpExtensionNone) {
       // Extensions are registered with an ID, which you signal to the
       // peer so they know what to expect. This code only cares about
       // parsing so the value of the ID isn't relevant; we use i.
-      extensions.Register(extension_type, i);
+      extensions.RegisterByType(i, extension_type);
     }
   }
 
   RtpPacketReceived packet(&extensions);
   packet.Parse(data, size);
 
   // Call packet accessors because they have extra checks.
   packet.Marker();
@@ -80,12 +81,22 @@ void FuzzOneInput(const uint8_t* data, s
       case kRtpExtensionTransportSequenceNumber:
         uint16_t seqnum;
         packet.GetExtension<TransportSequenceNumber>(&seqnum);
         break;
       case kRtpExtensionPlayoutDelay:
         PlayoutDelay playout;
         packet.GetExtension<PlayoutDelayLimits>(&playout);
         break;
+      case kRtpExtensionRtpStreamId: {
+        std::string rsid;
+        packet.GetExtension<RtpStreamId>(&rsid);
+        break;
+      }
+      case kRtpExtensionRepairedRtpStreamId: {
+        std::string rsid;
+        packet.GetExtension<RepairedRtpStreamId>(&rsid);
+        break;
+      }
     }
   }
 }
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
+++ b/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
@@ -385,18 +385,18 @@ bool RtpStreamReceiver::DeliverRtp(const
       ss << "Packet received on SSRC: " << header.ssrc << " with payload type: "
          << static_cast<int>(header.payloadType) << ", timestamp: "
          << header.timestamp << ", sequence number: " << header.sequenceNumber
          << ", arrival time: " << arrival_time_ms;
       if (header.extension.hasTransmissionTimeOffset)
         ss << ", toffset: " << header.extension.transmissionTimeOffset;
       if (header.extension.hasAbsoluteSendTime)
         ss << ", abs send time: " << header.extension.absoluteSendTime;
-			if (header.extension.hasRID)
-				ss << ", rid: " << header.extension.rid.get();
+      if (!header.extension.rtpStreamId.empty())
+        ss << ", rid: " << header.extension.rtpStreamId.data();
       LOG(LS_INFO) << ss.str();
       last_packet_log_ms_ = now_ms;
     }
   }
 
   remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_length,
                                             header);
   header.payload_type_frequency = kVideoPayloadTypeFrequency;
--- a/media/webrtc/trunk/webrtc/video/video_send_stream.cc
+++ b/media/webrtc/trunk/webrtc/video/video_send_stream.cc
@@ -22,16 +22,17 @@
 #include "webrtc/base/file.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/trace_event.h"
 #include "webrtc/base/weak_ptr.h"
 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
 #include "webrtc/modules/congestion_controller/include/congestion_controller.h"
 #include "webrtc/modules/pacing/packet_router.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
 #include "webrtc/modules/utility/include/process_thread.h"
 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
 #include "webrtc/system_wrappers/include/field_trial.h"
 #include "webrtc/video/call_stats.h"
 #include "webrtc/video/vie_remb.h"
 #include "webrtc/video_send_stream.h"
 
 namespace webrtc {
@@ -125,17 +126,17 @@ std::unique_ptr<FlexfecSender> MaybeCrea
            "To avoid confusion, disabling FlexFEC completely.";
     return nullptr;
   }
 
   RTC_DCHECK_EQ(1U, config.rtp.flexfec.protected_media_ssrcs.size());
   return std::unique_ptr<FlexfecSender>(new FlexfecSender(
       config.rtp.flexfec.payload_type, config.rtp.flexfec.ssrc,
       config.rtp.flexfec.protected_media_ssrcs[0], config.rtp.extensions,
-      Clock::GetRealTimeClock()));
+      RTPSender::FecExtensionSizes(), Clock::GetRealTimeClock()));
 }
 
 }  // namespace
 
 std::string
 VideoSendStream::Config::EncoderSettings::ToString() const {
   std::stringstream ss;
   ss << "{payload_name: " << payload_name;
--- a/mobile/android/app/src/australis/res/layout/toolbar_edit_layout.xml
+++ b/mobile/android/app/src/australis/res/layout/toolbar_edit_layout.xml
@@ -17,16 +17,17 @@
         android:paddingBottom="@dimen/browser_toolbar_site_security_padding_vertical"
         android:paddingLeft="@dimen/browser_toolbar_site_security_padding_horizontal"
         android:paddingStart="@dimen/browser_toolbar_site_security_padding_horizontal"
         android:paddingRight="@dimen/browser_toolbar_site_security_padding_horizontal"
         android:paddingEnd="@dimen/browser_toolbar_site_security_padding_horizontal"
         android:paddingTop="@dimen/browser_toolbar_site_security_padding_vertical"
         android:scaleType="fitCenter"
         android:src="@drawable/ic_search_icon"
+        android:background="@android:color/transparent"
         android:visibility="gone"/>
 
     <org.mozilla.gecko.toolbar.ToolbarEditText
           android:id="@+id/url_edit_text"
           style="@style/UrlBar.Title"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:layout_weight="1.0"
--- a/mobile/android/app/src/photon/java/org/mozilla/gecko/home/SearchEngineRow.java
+++ b/mobile/android/app/src/photon/java/org/mozilla/gecko/home/SearchEngineRow.java
@@ -210,24 +210,20 @@ class SearchEngineRow extends ThemedRela
         }
 
         final TextView suggestionText = (TextView) v.findViewById(R.id.suggestion_text);
         final String searchTerm = getSuggestionTextFromView(mUserEnteredView);
         final int searchTermLength = searchTerm.length();
         refreshOccurrencesWith(searchTerm, suggestion);
         if (mOccurrences.size() > 0) {
             final SpannableStringBuilder sb = new SpannableStringBuilder(suggestion);
-            int nextStartSpanIndex = 0;
-            // Done to make sure that the stretch of text after the last occurrence, till the end of the suggestion, is made bold
-            mOccurrences.add(suggestion.length());
             for (int occurrence : mOccurrences) {
                 // Even though they're the same style, SpannableStringBuilder will interpret there as being only one Span present if we re-use a StyleSpan
-                StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
-                sb.setSpan(boldSpan, nextStartSpanIndex, occurrence, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
-                nextStartSpanIndex = occurrence + searchTermLength;
+                final StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
+                sb.setSpan(boldSpan, occurrence, occurrence + searchTermLength, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
             }
             mOccurrences.clear();
             suggestionText.setText(sb);
         } else {
             suggestionText.setText(suggestion);
         }
 
         setDescriptionOnSuggestion(suggestionText, suggestion);
@@ -240,17 +236,20 @@ class SearchEngineRow extends ThemedRela
         String searchTerm = getSuggestionTextFromView(mUserEnteredView);
         if (mSearchListener != null) {
             Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "user");
             mSearchListener.onSearch(mSearchEngine, searchTerm, TelemetryContract.Method.SUGGESTION);
         }
     }
 
     public void setSearchTerm(String searchTerm) {
-        mUserEnteredTextView.setText(searchTerm);
+        final SpannableStringBuilder sb = new SpannableStringBuilder(searchTerm);
+        final StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
+        sb.setSpan(boldSpan, 0, searchTerm.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+        mUserEnteredTextView.setText(sb);
 
         // mSearchEngine is not set in the first call to this method; the content description
         // is instead initially set in updateSuggestions().
         if (mSearchEngine != null) {
             setDescriptionOnSuggestion(mUserEnteredTextView, searchTerm);
         }
     }
 
--- a/mobile/android/app/src/photon/res/layout/suggestion_item.xml
+++ b/mobile/android/app/src/photon/res/layout/suggestion_item.xml
@@ -25,18 +25,18 @@
         android:layout_marginEnd="3dip"
         android:layout_marginRight="3dip"
         android:src="@drawable/icon_most_recent_empty"
         android:visibility="gone"
         tools:visibility="visible"/>
 
     <org.mozilla.gecko.widget.themed.ThemedTextView
         android:id="@+id/suggestion_text"
+        style="@style/TextAppearance.SearchSuggestion"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:gravity="center_vertical"
         android:lineSpacingMultiplier="1.1"
         android:textColor="@color/search_suggestion_text"
-        android:textSize="14sp"
         tools:text="suggestion text"/>
 
 </org.mozilla.gecko.home.SuggestionItem>
--- a/mobile/android/app/src/photon/res/values-v16/styles.xml
+++ b/mobile/android/app/src/photon/res/values-v16/styles.xml
@@ -21,9 +21,12 @@
     <style name="TextAppearance.FirstrunTextRegular">
         <item name="android:fontFamily">sans-serif</item>
     </style>
 
     <style name="TextAppearance.UrlBar.Title" parent="TextAppearance.Small">
         <item name="android:textSize">16sp</item>
     </style>
 
+    <style name="TextAppearance.SearchSuggestion" parent="TextAppearance.Small">
+        <item name="android:fontFamily">sans-serif-light</item>
+    </style>
 </resources>
--- a/mobile/android/app/src/photon/res/values/styles.xml
+++ b/mobile/android/app/src/photon/res/values/styles.xml
@@ -427,16 +427,18 @@
     <style name="TextAppearance.DoorHanger.Small">
         <item name="android:textSize">14sp</item>
     </style>
 
     <style name="TextAppearance.UrlBar.Title" parent="TextAppearance.Small">
         <item name="android:textSize">16sp</item>
     </style>
 
+    <style name="TextAppearance.SearchSuggestion" parent="TextAppearance.Small"/>
+
     <!-- BrowserToolbar -->
     <style name="BrowserToolbar">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">@dimen/browser_toolbar_height</item>
         <item name="android:orientation">horizontal</item>
     </style>
 
     <!-- URL bar -->
--- a/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java
@@ -28,26 +28,33 @@ import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserContract.History;
 import org.mozilla.gecko.db.BrowserContract.URLColumns;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 import org.mozilla.gecko.home.SearchLoader.SearchCursorLoader;
 import org.mozilla.gecko.preferences.GeckoPreferences;
+import org.mozilla.gecko.skin.SkinConfig;
 import org.mozilla.gecko.toolbar.AutocompleteHandler;
 import org.mozilla.gecko.util.BundleEventListener;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.StringUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.graphics.Typeface;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.style.StyleSpan;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.v4.app.LoaderManager.LoaderCallbacks;
 import android.support.v4.content.AsyncTaskLoader;
 import android.support.v4.content.Loader;
 import android.text.TextUtils;
@@ -1184,22 +1191,57 @@ public class BrowserSearch extends HomeF
                 row.updateSuggestions(mSuggestionsEnabled, engine, mSearchHistorySuggestions);
                 row.setPrivateMode(isPrivate);
             } else {
                 // Account for the search engines
                 position -= getPrimaryEngineCount();
 
                 final Cursor c = getCursor(position);
                 final TwoLinePageRow row = (TwoLinePageRow) view;
+
+                if (SkinConfig.isPhoton()) {
+                    // Highlight all substrings in title field if they matches the search term.
+                    row.setTitleFormatter(mTwoLinePageRowTitleFormatter);
+                }
                 row.updateFromCursor(c);
                 row.setPrivateMode(isPrivate);
             }
         }
     }
 
+    private TwoLinePageRow.TitleFormatter mTwoLinePageRowTitleFormatter = new TwoLinePageRow.TitleFormatter() {
+        @Override
+        public CharSequence format(@NonNull CharSequence title) {
+            // Don't try to search for an empty string - String.indexOf will return 0, which would result
+            // in us iterating with lastIndexOfMatch = 0, which eventually results in an OOM.
+            if (TextUtils.isEmpty(mSearchTerm)) {
+                return title;
+            }
+
+            // Find matching substrings in title field in TwoLinePageRow, ignoring cases.
+            final String titleInLowerCase = title.toString().toLowerCase();
+            final String pattern = mSearchTerm.toLowerCase();
+            final int patternLength = pattern.length();
+
+            final SpannableStringBuilder sb = new SpannableStringBuilder(title);
+
+            int indexOfMatch = 0;
+            int lastIndexOfMatch = 0;
+            while (indexOfMatch != -1) {
+                indexOfMatch = titleInLowerCase.indexOf(pattern, lastIndexOfMatch);
+                lastIndexOfMatch = indexOfMatch + patternLength;
+                if (indexOfMatch != -1) {
+                    final StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
+                    sb.setSpan(boldSpan, indexOfMatch, lastIndexOfMatch, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+                }
+            }
+            return sb;
+        }
+    };
+
     private class CursorLoaderCallbacks implements LoaderCallbacks<Cursor> {
         @Override
         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
             return SearchLoader.createInstance(getActivity(), args);
         }
 
         @Override
         public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
--- a/mobile/android/base/java/org/mozilla/gecko/home/TwoLinePageRow.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/TwoLinePageRow.java
@@ -4,18 +4,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.home;
 
 import java.util.concurrent.Future;
 
 import android.content.Context;
 import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.TextViewCompat;
+import android.text.Spannable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
 
 import org.mozilla.gecko.R;
@@ -50,16 +53,18 @@ public class TwoLinePageRow extends Them
 
     private boolean mShowIcons;
 
     // The URL for the page corresponding to this view.
     private String mPageUrl;
 
     private boolean mHasReaderCacheItem;
 
+    private TitleFormatter mTitleFormatter;
+
     public TwoLinePageRow(Context context) {
         this(context, null);
     }
 
     public TwoLinePageRow(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         setGravity(Gravity.CENTER_VERTICAL);
@@ -136,17 +141,17 @@ public class TwoLinePageRow extends Them
             case LOCATION_CHANGE:
                 updateDisplayedUrl();
                 break;
             default:
                 break;
         }
     }
 
-    private void setTitle(String text) {
+    private void setTitle(CharSequence text) {
         mTitle.setText(text);
     }
 
     protected void setUrl(String text) {
         mUrl.setText(text);
     }
 
     protected void setUrl(int stringId) {
@@ -244,17 +249,22 @@ public class TwoLinePageRow extends Them
 
             updateStatusIcon(isBookmark, hasReaderCacheItem);
         } else {
             updateStatusIcon(false, false);
         }
 
         // Use the URL instead of an empty title for consistency with the normal URL
         // bar view - this is the equivalent of getDisplayTitle() in Tab.java
-        setTitle(TextUtils.isEmpty(title) ? url : title);
+        final String titleToShow = TextUtils.isEmpty(title) ? url : title;
+        if (mTitleFormatter != null) {
+            setTitle(mTitleFormatter.format(titleToShow));
+        } else {
+            setTitle(titleToShow);
+        }
 
         // No point updating the below things if URL has not changed. Prevents evil Favicon flicker.
         if (url.equals(mPageUrl)) {
             return;
         }
 
         // Blank the Favicon, so we don't show the wrong Favicon if we scroll and miss DB.
         mFavicon.clearImage();
@@ -324,9 +334,18 @@ public class TwoLinePageRow extends Them
             bookmarkId = 0;
         }
 
         SavedReaderViewHelper rch = SavedReaderViewHelper.getSavedReaderViewHelper(getContext());
         final boolean hasReaderCacheItem = rch.isURLCached(url);
 
         update(title, url, bookmarkId, hasReaderCacheItem);
     }
+
+    public void setTitleFormatter(TitleFormatter formatter) {
+        mTitleFormatter = formatter;
+    }
+
+    // Use this interface to decorate content in title view.
+    interface TitleFormatter {
+        CharSequence format(@NonNull CharSequence title);
+    }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/widget/FadedSingleColorTextView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/FadedSingleColorTextView.java
@@ -49,17 +49,18 @@ public class FadedSingleColorTextView ex
         getPaint().setShader(needsEllipsis ? mTextGradient : null);
     }
 
     @Override
     public void setText(CharSequence text, BufferType type) {
         super.setText(text, type);
         final boolean previousTextDirectionRtl = mIsTextDirectionRtl;
         if (!TextUtils.isEmpty(text)) {
-            mIsTextDirectionRtl = BidiFormatter.getInstance().isRtl((String) text);
+            // The text is an instance of CharSequence, not String. It cannot cast to String directly, use toString() instead.
+            mIsTextDirectionRtl = BidiFormatter.getInstance().isRtl(text.toString());
         }
         if (mIsTextDirectionRtl != previousTextDirectionRtl) {
             mTextGradient = null;
         }
         ViewUtil.setTextDirectionRtlCompat(this, mIsTextDirectionRtl);
     }
 
     @Override
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
@@ -288,21 +288,31 @@ final class GeckoEditable extends IGecko
             }
 
             // Copy the portion of the current text that has changed over to the shadow
             // text, with consideration for any concurrent changes in the shadow text.
             final int start = Math.min(mShadowStart, mCurrentStart);
             final int shadowEnd = mShadowNewEnd + Math.max(0, mCurrentOldEnd - mShadowOldEnd);
             final int currentEnd = mCurrentNewEnd + Math.max(0, mShadowOldEnd - mCurrentOldEnd);
 
-            // Perform replacement in two steps (delete and insert) so that old spans are
-            // properly deleted before identical new spans are inserted. Otherwise the new
-            // spans won't be inserted due to the text already having the old spans.
-            mShadowText.delete(start, shadowEnd);
-            mShadowText.insert(start, mCurrentText, start, currentEnd);
+            // Remove identical spans that are in the new text from the old text.
+            // Otherwise the new spans won't be inserted due to the text already having
+            // the old spans.
+            Object[] spans = mCurrentText.getSpans(start, currentEnd, Object.class);
+            for (final Object span : spans) {
+                mShadowText.removeSpan(span);
+            }
+
+            // Also remove existing spans that are no longer in the new text.
+            spans = mShadowText.getSpans(start, shadowEnd, Object.class);
+            for (final Object span : spans) {
+                mShadowText.removeSpan(span);
+            }
+
+            mShadowText.replace(start, shadowEnd, mCurrentText, start, currentEnd);
 
             // SpannableStringBuilder has some internal logic to fix up selections, but we
             // don't want that, so we always fix up the selection a second time.
             final int selStart = Selection.getSelectionStart(mCurrentText);
             final int selEnd = Selection.getSelectionEnd(mCurrentText);
             Selection.setSelection(mShadowText, selStart, selEnd);
 
             if (DEBUG && !checkEqualText(mShadowText, mCurrentText)) {
--- a/security/sandbox/linux/Sandbox.cpp
+++ b/security/sandbox/linux/Sandbox.cpp
@@ -560,29 +560,40 @@ SandboxEarlyInit(GeckoProcessType aType)
   bool canChroot = false;
   bool canUnshareNet = false;
   bool canUnshareIPC = false;
 
   switch (aType) {
   case GeckoProcessType_Default:
     MOZ_ASSERT(false, "SandboxEarlyInit in parent process");
     return;
+
 #ifdef MOZ_GMP_SANDBOX
   case GeckoProcessType_GMPlugin:
     if (!info.Test(SandboxInfo::kEnabledForMedia)) {
       break;
     }
     canUnshareNet = true;
     canUnshareIPC = true;
     // Need seccomp-bpf to intercept open().
     canChroot = info.Test(SandboxInfo::kHasSeccompBPF);
     break;
 #endif
-    // In the future, content processes will be able to use some of
-    // these.
+
+#ifdef MOZ_CONTENT_SANDBOX
+  case GeckoProcessType_Content:
+    if (!info.Test(SandboxInfo::kEnabledForContent)) {
+      break;
+    }
+#ifndef MOZ_ALSA
+    canUnshareIPC = true;
+#endif
+    break;
+#endif
+
   default:
     // Other cases intentionally left blank.
     break;
   }
 
   // If TSYNC is not supported, set up signal handler
   // used to enable seccomp on each thread.
   if (!info.Test(SandboxInfo::kHasSeccompTSync)) {
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ b/security/sandbox/linux/SandboxFilter.cpp
@@ -563,28 +563,23 @@ public:
     default:
       return SandboxPolicyCommon::EvaluateSocketCall(aCall);
     }
   }
 
 #ifdef DESKTOP
   Maybe<ResultExpr> EvaluateIpcCall(int aCall) const override {
     switch(aCall) {
-      // These are a problem: SysV shared memory follows the Unix
-      // "same uid policy" and can't be restricted/brokered like file
-      // access.  But the graphics layer might not be using them
-      // anymore; this needs to be studied.
-    case SHMGET:
-    case SHMCTL:
-    case SHMAT:
-    case SHMDT:
+      // SysV IPC is a problem: it follows the Unix "same uid policy"
+      // and can't be restricted/brokered like file access.
+#ifdef MOZ_ALSA
     case SEMGET:
     case SEMCTL:
     case SEMOP:
-    case MSGGET:
+#endif
       return Some(Allow());
     default:
       return SandboxPolicyCommon::EvaluateIpcCall(aCall);
     }
   }
 #endif
 
   ResultExpr EvaluateSyscall(int sysno) const override {
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -1019,16 +1019,17 @@ dependencies = [
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "nsstring_vendor 0.1.0",
  "parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
+ "servo_arc 0.0.1",
  "style 0.0.1",
  "style_traits 0.0.1",
  "stylo_tests 0.0.1",
 ]
 
 [[package]]
 name = "getopts"
 version = "0.2.14"
@@ -1058,16 +1059,17 @@ dependencies = [
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "range 0.0.1",
  "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_arc 0.0.1",
  "servo_atoms 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1456,16 +1458,17 @@ dependencies = [
  "profile_traits 0.0.1",
  "range 0.0.1",
  "rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.19.0",
  "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_arc 0.0.1",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1504,16 +1507,17 @@ dependencies = [
  "profile_traits 0.0.1",
  "range 0.0.1",
  "rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.19.0",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_arc 0.0.1",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
  "webrender_api 0.48.0 (git+https://github.com/servo/webrender)",
 ]
 
@@ -2465,16 +2469,17 @@ dependencies = [
  "ref_slice 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_plugins 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.19.0",
  "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_arc 0.0.1",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_rand 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
@@ -2508,16 +2513,17 @@ dependencies = [
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.19.0",
+ "servo_arc 0.0.1",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
  "webrender_api 0.48.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "script_plugins"
@@ -3024,16 +3030,17 @@ dependencies = [
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
+ "servo_arc 0.0.1",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_url 0.0.1",
  "size_of_test 0.0.1",
  "style 0.0.1",
  "style_traits 0.0.1",
 ]
 
--- a/servo/components/constellation/pipeline.rs
+++ b/servo/components/constellation/pipeline.rs
@@ -70,19 +70,16 @@ pub struct Pipeline {
     /// A channel to the compositor.
     pub compositor_proxy: CompositorProxy,
 
     /// The most recently loaded URL in this pipeline.
     /// Note that this URL can change, for example if the page navigates
     /// to a hash URL.
     pub url: ServoUrl,
 
-    /// The title of the most recently-loaded page.
-    pub title: Option<String>,
-
     /// Whether this pipeline is currently running animations. Pipelines that are running
     /// animations cause composites to be continually scheduled.
     pub running_animations: bool,
 
     /// The child browsing contexts of this pipeline (these are iframes in the document).
     pub children: Vec<BrowsingContextId>,
 
     /// Whether this pipeline is in private browsing mode.
@@ -311,17 +308,16 @@ impl Pipeline {
             id: id,
             browsing_context_id: browsing_context_id,
             top_level_browsing_context_id: top_level_browsing_context_id,
             parent_info: parent_info,
             event_loop: event_loop,
             layout_chan: layout_chan,
             compositor_proxy: compositor_proxy,
             url: url,
-            title: None,
             children: vec!(),
             running_animations: false,
             visible: visible,
             is_private: is_private,
         };
 
         pipeline.notify_visibility();
 
--- a/servo/components/gfx/Cargo.toml
+++ b/servo/components/gfx/Cargo.toml
@@ -24,16 +24,17 @@ ipc-channel = "0.8"
 lazy_static = "0.2"
 libc = "0.2"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 ordered-float = "0.4"
 range = {path = "../range"}
 serde = "1.0"
+servo_arc = {path = "../servo_arc"}
 servo_atoms = {path = "../atoms"}
 servo_geometry = {path = "../geometry"}
 servo_url = {path = "../url"}
 smallvec = "0.4"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 time = "0.1.12"
 unicode-bidi = {version = "0.3", features = ["with_serde"]}
--- a/servo/components/gfx/font_context.rs
+++ b/servo/components/gfx/font_context.rs
@@ -6,27 +6,27 @@ use app_units::Au;
 use fnv::FnvHasher;
 use font::{Font, FontGroup, FontHandleMethods};
 use font_cache_thread::FontCacheThread;
 use font_template::FontTemplateDescriptor;
 use heapsize::HeapSizeOf;
 use platform::font::FontHandle;
 use platform::font_context::FontContextHandle;
 use platform::font_template::FontTemplateData;
+use servo_arc::Arc as ServoArc;
 use smallvec::SmallVec;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::default::Default;
 use std::hash::{BuildHasherDefault, Hash, Hasher};
 use std::rc::Rc;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
 use style::computed_values::{font_style, font_variant_caps};
 use style::properties::style_structs;
-use style::stylearc::Arc as StyleArc;
 use webrender_api;
 
 static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8;      // Matches FireFox (see gfxFont.h)
 
 #[derive(Debug)]
 struct LayoutFontCacheEntry {
     family: String,
     font: Option<Rc<RefCell<Font>>>,
@@ -105,17 +105,17 @@ impl FontContext {
         self.fallback_font_cache.clear();
         self.layout_font_group_cache.clear();
         self.epoch = current_epoch
     }
 
     /// Create a group of fonts for use in layout calculations. May return
     /// a cached font if this font instance has already been used by
     /// this context.
-    pub fn layout_font_group_for_style(&mut self, style: StyleArc<style_structs::Font>)
+    pub fn layout_font_group_for_style(&mut self, style: ServoArc<style_structs::Font>)
                                        -> Rc<FontGroup> {
         self.expire_font_caches_if_necessary();
 
         let layout_font_group_cache_key = LayoutFontGroupCacheKey {
             pointer: style.clone(),
             size: style.font_size,
         };
         if let Some(ref cached_font_group) = self.layout_font_group_cache.get(
@@ -235,17 +235,17 @@ impl HeapSizeOf for FontContext {
     fn heap_size_of_children(&self) -> usize {
         // FIXME(njn): Measure other fields eventually.
         self.platform_handle.heap_size_of_children()
     }
 }
 
 #[derive(Debug)]
 struct LayoutFontGroupCacheKey {
-    pointer: StyleArc<style_structs::Font>,
+    pointer: ServoArc<style_structs::Font>,
     size: Au,
 }
 
 impl PartialEq for LayoutFontGroupCacheKey {
     fn eq(&self, other: &LayoutFontGroupCacheKey) -> bool {
         self.pointer == other.pointer && self.size == other.size
     }
 }
--- a/servo/components/gfx/lib.rs
+++ b/servo/components/gfx/lib.rs
@@ -47,16 +47,17 @@ extern crate lazy_static;
 extern crate libc;
 #[macro_use]
 extern crate log;
 extern crate msg;
 extern crate net_traits;
 extern crate ordered_float;
 extern crate range;
 #[macro_use] extern crate serde;
+extern crate servo_arc;
 extern crate servo_geometry;
 extern crate servo_url;
 #[macro_use] extern crate servo_atoms;
 #[cfg(any(target_feature = "sse2", target_feature = "neon"))]
 extern crate simd;
 extern crate smallvec;
 extern crate style;
 extern crate style_traits;
--- a/servo/components/layout/Cargo.toml
+++ b/servo/components/layout/Cargo.toml
@@ -29,16 +29,17 @@ ordered-float = "0.4"
 parking_lot = "0.4"
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 rayon = "0.8"
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = { path = "../selectors" }
 serde = "1.0"
+servo_arc = {path = "../servo_arc"}
 servo_atoms = {path = "../atoms"}
 servo_geometry = {path = "../geometry"}
 serde_json = "1.0"
 servo_config = {path = "../config"}
 servo_url = {path = "../url"}
 smallvec = "0.4"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -2134,17 +2134,17 @@ impl Flow for BlockFlow {
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.collect_stacking_contexts_for_block(state);
     }
 
     fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
         self.build_display_list_for_block(state, BorderPaintingMode::Separate);
     }
 
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
         self.fragment.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         let flow_size = self.base.position.size.to_physical(self.base.writing_mode);
         let overflow = self.fragment.compute_overflow(&flow_size,
                                        &self.base
                                             .early_absolute_position_info
--- a/servo/components/layout/construct.rs
+++ b/servo/components/layout/construct.rs
@@ -8,17 +8,17 @@
 //! not dirty and an existing flow exists, then the traversal reuses that flow. Otherwise, it
 //! proceeds to construct either a flow or a `ConstructionItem`. A construction item is a piece of
 //! intermediate data that goes with a DOM node and hasn't found its "home" yet-maybe it's a box,
 //! maybe it's an absolute or fixed position thing that hasn't found its containing block yet.
 //! Construction items bubble up the tree from children to parents until they find their homes.
 
 #![deny(unsafe_code)]
 
-use StyleArc;
+use ServoArc;
 use app_units::Au;
 use block::BlockFlow;
 use context::{LayoutContext, with_thread_local_font_context};
 use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutData};
 use flex::FlexFlow;
 use floats::FloatKind;
 use flow::{self, AbsoluteDescendants, Flow, FlowClass, ImmutableFlowUtils};
 use flow::{CAN_BE_FRAGMENTED, IS_ABSOLUTELY_POSITIONED, MARGINS_CANNOT_COLLAPSE};
@@ -104,17 +104,17 @@ impl ConstructionResult {
 /// Represents the output of flow construction for a DOM node that has not yet resulted in a
 /// complete flow. Construction items bubble up the tree until they find a `Flow` to be attached
 /// to.
 #[derive(Clone)]
 pub enum ConstructionItem {
     /// Inline fragments and associated {ib} splits that have not yet found flows.
     InlineFragments(InlineFragmentsConstructionResult),
     /// Potentially ignorable whitespace.
-    Whitespace(OpaqueNode, PseudoElementType<()>, StyleArc<ComputedValues>, RestyleDamage),
+    Whitespace(OpaqueNode, PseudoElementType<()>, ServoArc<ComputedValues>, RestyleDamage),
     /// TableColumn Fragment
     TableColumnFragment(Fragment),
 }
 
 /// Represents inline fragments and {ib} splits that are bubbling up from an inline.
 #[derive(Clone)]
 pub struct InlineFragmentsConstructionResult {
     /// Any {ib} splits that we're bubbling up.
@@ -672,17 +672,17 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
         }
         self.build_flow_for_block_starting_with_fragments(flow, node, fragments)
     }
 
     /// Pushes fragments appropriate for the content of the given node onto the given list.
     fn create_fragments_for_node_text_content(&self,
                                               fragments: &mut IntermediateInlineFragments,
                                               node: &ConcreteThreadSafeLayoutNode,
-                                              style: &StyleArc<ComputedValues>) {
+                                              style: &ServoArc<ComputedValues>) {
         // Fast path: If there is no text content, return immediately.
         let text_content = node.text_content();
         if text_content.is_empty() {
             return
         }
 
         let style = (*style).clone();
         let selected_style = node.selected_style();
@@ -1801,17 +1801,17 @@ pub fn strip_ignorable_whitespace_from_e
             }
         }
     }
     this.append(&mut trailing_fragments_consisting_of_solely_bidi_control_characters);
 }
 
 /// If the 'unicode-bidi' property has a value other than 'normal', return the bidi control codes
 /// to inject before and after the text content of the element.
-fn bidi_control_chars(style: &StyleArc<ComputedValues>) -> Option<(&'static str, &'static str)> {
+fn bidi_control_chars(style: &ServoArc<ComputedValues>) -> Option<(&'static str, &'static str)> {
     use style::computed_values::direction::T::*;
     use style::computed_values::unicode_bidi::T::*;
 
     let unicode_bidi = style.get_text().unicode_bidi;
     let direction = style.get_inheritedbox().direction;
 
     // See the table in http://dev.w3.org/csswg/css-writing-modes/#unicode-bidi
     match (unicode_bidi, direction) {
--- a/servo/components/layout/flex.rs
+++ b/servo/components/layout/flex.rs
@@ -968,17 +968,17 @@ impl Flow for FlexFlow {
     fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
         self.build_display_list_for_flex(state);
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         self.block_flow.compute_overflow()
     }
 
     fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
--- a/servo/components/layout/flow.rs
+++ b/servo/components/layout/flow.rs
@@ -419,17 +419,17 @@ pub trait Flow: fmt::Debug + Sync + Send
     /// positioned descendant referenced by `for_flow`. For block flows, this is the padding box.
     ///
     /// NB: Do not change this `&self` to `&mut self` under any circumstances! It has security
     /// implications because this can be called on parents concurrently from descendants!
     fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au>;
 
     /// Attempts to perform incremental fixup of this flow by replacing its fragment's style with
     /// the new style. This can only succeed if the flow has exactly one fragment.
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>);
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>);
 
     /// Print any extra children (such as fragments) contained in this Flow
     /// for debugging purposes. Any items inserted into the tree will become
     /// children of this flow.
     fn print_extra_flow_children(&self, _: &mut PrintTree) { }
 
     fn scroll_root_id(&self, pipeline_id: PipelineId) -> ClipId {
         match base(self).scroll_root_id {
@@ -556,17 +556,17 @@ pub trait MutableFlowUtils {
     /// Return true if the traversal is to continue or false to stop.
     fn traverse_postorder_absolute_flows<T>(&mut self, traversal: &mut T)
                                             where T: PostorderFlowTraversal;
 
     // Mutators
 
     /// Calls `repair_style` and `bubble_inline_sizes`. You should use this method instead of
     /// calling them individually, since there is no reason not to perform both operations.
-    fn repair_style_and_bubble_inline_sizes(self, style: &::StyleArc<ComputedValues>);
+    fn repair_style_and_bubble_inline_sizes(self, style: &::ServoArc<ComputedValues>);
 }
 
 pub trait MutableOwnedFlowUtils {
     /// Set absolute descendants for this flow.
     ///
     /// Set this flow as the Containing Block for all the absolute descendants.
     fn set_absolute_descendants(&mut self, abs_descendants: AbsoluteDescendants);
 
@@ -1376,17 +1376,17 @@ impl<'a> MutableFlowUtils for &'a mut Fl
         if traversal.should_process(self) {
             traversal.process(self)
         }
     }
 
 
     /// Calls `repair_style` and `bubble_inline_sizes`. You should use this method instead of
     /// calling them individually, since there is no reason not to perform both operations.
-    fn repair_style_and_bubble_inline_sizes(self, style: &::StyleArc<ComputedValues>) {
+    fn repair_style_and_bubble_inline_sizes(self, style: &::ServoArc<ComputedValues>) {
         self.repair_style(style);
         mut_base(self).update_flags_if_needed(style);
         self.bubble_inline_sizes();
     }
 
     /// Traverse the Absolute flow tree in preorder.
     ///
     /// Traverse all your direct absolute descendants, who will then traverse
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! The `Fragment` type, which represents the leaves of the layout tree.
 
 #![deny(unsafe_code)]
 
-use StyleArc;
+use ServoArc;
 use app_units::Au;
 use canvas_traits::CanvasMsg;
 use context::{LayoutContext, with_thread_local_font_context};
 use euclid::{Transform3D, Point2D, Vector2D, Radians, Rect, Size2D};
 use floats::ClearType;
 use flow::{self, ImmutableFlowUtils};
 use flow_ref::FlowRef;
 use gfx;
@@ -90,20 +90,20 @@ static DEFAULT_REPLACED_HEIGHT: i32 = 15
 /// FIXME(#2260, pcwalton): This can be slimmed down some by (at least) moving `inline_context`
 /// to be on `InlineFlow` only.
 #[derive(Clone)]
 pub struct Fragment {
     /// An opaque reference to the DOM node that this `Fragment` originates from.
     pub node: OpaqueNode,
 
     /// The CSS style of this fragment.
-    pub style: StyleArc<ComputedValues>,
+    pub style: ServoArc<ComputedValues>,
 
     /// The CSS style of this fragment when it's selected
-    pub selected_style: StyleArc<ComputedValues>,
+    pub selected_style: ServoArc<ComputedValues>,
 
     /// The position of this fragment relative to its owning flow. The size includes padding and
     /// border, but not margin.
     ///
     /// NB: This does not account for relative positioning.
     /// NB: Collapsed borders are not included in this.
     pub border_box: LogicalRect<Au>,
 
@@ -671,18 +671,18 @@ impl Fragment {
             debug_id: DebugId::new(),
             stacking_context_id: StackingContextId::root(),
         }
     }
 
     /// Constructs a new `Fragment` instance from an opaque node.
     pub fn from_opaque_node_and_style(node: OpaqueNode,
                                       pseudo: PseudoElementType<()>,
-                                      style: StyleArc<ComputedValues>,
-                                      selected_style: StyleArc<ComputedValues>,
+                                      style: ServoArc<ComputedValues>,
+                                      selected_style: ServoArc<ComputedValues>,
                                       mut restyle_damage: RestyleDamage,
                                       specific: SpecificFragmentInfo)
                                       -> Fragment {
         let writing_mode = style.writing_mode;
 
         restyle_damage.remove(RECONSTRUCT_FLOW);
 
         Fragment {
@@ -701,17 +701,17 @@ impl Fragment {
             stacking_context_id: StackingContextId::root(),
         }
     }
 
     /// Creates an anonymous fragment just like this one but with the given style and fragment
     /// type. For the new anonymous fragment, layout-related values (border box, etc.) are reset to
     /// initial values.
     pub fn create_similar_anonymous_fragment(&self,
-                                             style: StyleArc<ComputedValues>,
+                                             style: ServoArc<ComputedValues>,
                                              specific: SpecificFragmentInfo)
                                              -> Fragment {
         let writing_mode = style.writing_mode;
         Fragment {
             node: self.node,
             style: style,
             selected_style: self.selected_style.clone(),
             restyle_damage: self.restyle_damage,
@@ -2418,17 +2418,17 @@ impl Fragment {
     pub fn update_late_computed_block_position_if_necessary(&mut self) {
         if let SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) = self.specific {
             let position = self.border_box.start.b;
             FlowRef::deref_mut(&mut info.flow_ref)
                 .update_late_computed_block_position_if_necessary(position)
         }
     }
 
-    pub fn repair_style(&mut self, new_style: &StyleArc<ComputedValues>) {
+    pub fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
         self.style = (*new_style).clone()
     }
 
     /// Given the stacking-context-relative position of the containing flow, returns the border box
     /// of this fragment relative to the parent stacking context. This takes `position: relative`
     /// into account.
     ///
     /// If `coordinate_system` is `Parent`, this returns the border box in the parent stacking
--- a/servo/components/layout/generated_content.rs
+++ b/servo/components/layout/generated_content.rs
@@ -363,17 +363,17 @@ impl Counter {
             value: amount,
         })
     }
 
     fn render(&self,
               layout_context: &LayoutContext,
               node: OpaqueNode,
               pseudo: PseudoElementType<()>,
-              style: ::StyleArc<ComputedValues>,
+              style: ::ServoArc<ComputedValues>,
               list_style_type: list_style_type::T,
               mode: RenderingMode)
               -> Option<SpecificFragmentInfo> {
         let mut string = String::new();
         match mode {
             RenderingMode::Plain => {
                 let value = match self.values.last() {
                     Some(ref value) => value.value,
@@ -426,17 +426,17 @@ struct CounterValue {
     /// The value of the counter at this level.
     value: i32,
 }
 
 /// Creates fragment info for a literal string.
 fn render_text(layout_context: &LayoutContext,
                node: OpaqueNode,
                pseudo: PseudoElementType<()>,
-               style: ::StyleArc<ComputedValues>,
+               style: ::ServoArc<ComputedValues>,
                string: String)
                -> Option<SpecificFragmentInfo> {
     let mut fragments = LinkedList::new();
     let info = SpecificFragmentInfo::UnscannedText(
         box UnscannedTextFragmentInfo::new(string, None));
     fragments.push_back(Fragment::from_opaque_node_and_style(node,
                                                              pseudo,
                                                              style.clone(),
--- a/servo/components/layout/inline.rs
+++ b/servo/components/layout/inline.rs
@@ -1,15 +1,15 @@
 /* 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/. */
 
 #![deny(unsafe_code)]
 
-use StyleArc;
+use ServoArc;
 use app_units::{Au, MIN_AU};
 use block::AbsoluteAssignBSizesTraversal;
 use context::LayoutContext;
 use display_list_builder::{DisplayListBuildState, InlineFlowDisplayListBuilding};
 use euclid::{Point2D, Size2D};
 use floats::{FloatKind, Floats, PlacementInfo};
 use flow::{self, BaseFlow, Flow, FlowClass, ForceNonfloatedFlag};
 use flow::{CONTAINS_TEXT_OR_REPLACED_FRAGMENTS, EarlyAbsolutePositionInfo, MutableFlowUtils};
@@ -1660,17 +1660,17 @@ impl Flow for InlineFlow {
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.collect_stacking_contexts_for_inline(state);
     }
 
     fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
         self.build_display_list_for_inline(state);
     }
 
-    fn repair_style(&mut self, _: &StyleArc<ComputedValues>) {}
+    fn repair_style(&mut self, _: &ServoArc<ComputedValues>) {}
 
     fn compute_overflow(&self) -> Overflow {
         let mut overflow = Overflow::new();
         let flow_size = self.base.position.size.to_physical(self.base.writing_mode);
         let relative_containing_block_size =
             &self.base.early_absolute_position_info.relative_containing_block_size;
         for fragment in &self.fragments.fragments {
             overflow.union(&fragment.compute_overflow(&flow_size, &relative_containing_block_size))
@@ -1749,18 +1749,18 @@ impl fmt::Debug for InlineFlow {
                self.base.debug_id(),
                flow::base(self))
     }
 }
 
 #[derive(Clone)]
 pub struct InlineFragmentNodeInfo {
     pub address: OpaqueNode,
-    pub style: StyleArc<ComputedValues>,
-    pub selected_style: StyleArc<ComputedValues>,
+    pub style: ServoArc<ComputedValues>,
+    pub selected_style: ServoArc<ComputedValues>,
     pub pseudo: PseudoElementType<()>,
     pub flags: InlineFragmentNodeFlags,
 }
 
 bitflags! {
     pub flags InlineFragmentNodeFlags: u8 {
         const FIRST_FRAGMENT_OF_ELEMENT = 0x01,
         const LAST_FRAGMENT_OF_ELEMENT = 0x02,
--- a/servo/components/layout/lib.rs
+++ b/servo/components/layout/lib.rs
@@ -31,16 +31,17 @@ extern crate parking_lot;
 extern crate profile_traits;
 #[macro_use]
 extern crate range;
 extern crate rayon;
 extern crate script_layout_interface;
 extern crate script_traits;
 #[macro_use] extern crate serde;
 extern crate serde_json;
+extern crate servo_arc;
 extern crate servo_atoms;
 extern crate servo_config;
 extern crate servo_geometry;
 extern crate servo_url;
 extern crate smallvec;
 extern crate style;
 extern crate style_traits;
 extern crate unicode_bidi;
@@ -86,11 +87,11 @@ pub mod traversal;
 pub mod webrender_helpers;
 pub mod wrapper;
 
 // For unit tests:
 pub use fragment::Fragment;
 pub use fragment::SpecificFragmentInfo;
 pub use self::data::LayoutData;
 
-// We can't use stylearc for everything in layout, because the Flow stuff uses
+// We can't use servo_arc for everything in layout, because the Flow stuff uses
 // weak references.
-use style::stylearc::Arc as StyleArc;
+use servo_arc::Arc as ServoArc;
--- a/servo/components/layout/list_item.rs
+++ b/servo/components/layout/list_item.rs
@@ -142,17 +142,17 @@ impl Flow for ListItemFlow {
     fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
         self.build_display_list_for_list_item(state);
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         let mut overflow = self.block_flow.compute_overflow();
         let flow_size = self.block_flow.base.position.size.to_physical(self.block_flow.base.writing_mode);
         let relative_containing_block_size =
             &self.block_flow.base.early_absolute_position_info.relative_containing_block_size;
--- a/servo/components/layout/multicol.rs
+++ b/servo/components/layout/multicol.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! CSS Multi-column layout http://dev.w3.org/csswg/css-multicol/
 
 #![deny(unsafe_code)]
 
-use StyleArc;
+use ServoArc;
 use app_units::Au;
 use block::BlockFlow;
 use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::{Point2D, Vector2D};
 use floats::FloatKind;
 use flow::{Flow, FlowClass, OpaqueFlow, mut_base, FragmentationContext};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
@@ -188,17 +188,17 @@ impl Flow for MulticolFlow {
         debug!("build_display_list_multicol");
         self.block_flow.build_display_list(state);
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         self.block_flow.compute_overflow()
     }
 
     fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
@@ -270,17 +270,17 @@ impl Flow for MulticolColumnFlow {
         debug!("build_display_list_multicol column");
         self.block_flow.build_display_list(state);
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         self.block_flow.compute_overflow()
     }
 
     fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
--- a/servo/components/layout/table.rs
+++ b/servo/components/layout/table.rs
@@ -501,17 +501,17 @@ impl Flow for TableFlow {
 
         self.block_flow.build_display_list_for_block(state, border_painting_mode);
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         self.block_flow.compute_overflow()
     }
 
     fn iterate_through_fragment_border_boxes(&self,
--- a/servo/components/layout/table_caption.rs
+++ b/servo/components/layout/table_caption.rs
@@ -78,17 +78,17 @@ impl Flow for TableCaptionFlow {
         debug!("build_display_list_table_caption: same process as block flow");
         self.block_flow.build_display_list(state);
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         self.block_flow.compute_overflow()
     }
 
     fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
--- a/servo/components/layout/table_cell.rs
+++ b/servo/components/layout/table_cell.rs
@@ -258,17 +258,17 @@ impl Flow for TableCellFlow {
 
         self.block_flow.build_display_list_for_block(state, border_painting_mode)
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         self.block_flow.compute_overflow()
     }
 
     fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
--- a/servo/components/layout/table_colgroup.rs
+++ b/servo/components/layout/table_colgroup.rs
@@ -89,17 +89,17 @@ impl Flow for TableColGroupFlow {
 
     fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}
 
     // Table columns are invisible.
     fn build_display_list(&mut self, _: &mut DisplayListBuildState) { }
 
     fn collect_stacking_contexts(&mut self, _: &mut DisplayListBuildState) {}
 
-    fn repair_style(&mut self, _: &::StyleArc<ComputedValues>) {}
+    fn repair_style(&mut self, _: &::ServoArc<ComputedValues>) {}
 
     fn compute_overflow(&self) -> Overflow {
         Overflow::new()
     }
 
     fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au> {
         panic!("Table column groups can't be containing blocks!")
     }
--- a/servo/components/layout/table_row.rs
+++ b/servo/components/layout/table_row.rs
@@ -476,17 +476,17 @@ impl Flow for TableRowFlow {
 
         self.block_flow.build_display_list_for_block(state, border_painting_mode);
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         self.block_flow.compute_overflow()
     }
 
     fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
--- a/servo/components/layout/table_rowgroup.rs
+++ b/servo/components/layout/table_rowgroup.rs
@@ -180,17 +180,17 @@ impl Flow for TableRowGroupFlow {
         debug!("build_display_list_table_rowgroup: same process as block flow");
         self.block_flow.build_display_list(state);
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         self.block_flow.compute_overflow()
     }
 
     fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
--- a/servo/components/layout/table_wrapper.rs
+++ b/servo/components/layout/table_wrapper.rs
@@ -461,17 +461,17 @@ impl Flow for TableWrapperFlow {
     fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.build_display_list(state);
     }
 
     fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
         self.block_flow.collect_stacking_contexts(state);
     }
 
-    fn repair_style(&mut self, new_style: &::StyleArc<ComputedValues>) {
+    fn repair_style(&mut self, new_style: &::ServoArc<ComputedValues>) {
         self.block_flow.repair_style(new_style)
     }
 
     fn compute_overflow(&self) -> Overflow {
         self.block_flow.compute_overflow()
     }
 
     fn iterate_through_fragment_border_boxes(&self,
--- a/servo/components/layout/text.rs
+++ b/servo/components/layout/text.rs
@@ -431,17 +431,17 @@ fn bounding_box_for_run_metrics(metrics:
         metrics.bounding_box.size.width,
         metrics.bounding_box.size.height)
 }
 
 /// Returns the metrics of the font represented by the given `style_structs::Font`, respectively.
 ///
 /// `#[inline]` because often the caller only needs a few fields from the font metrics.
 #[inline]
-pub fn font_metrics_for_style(font_context: &mut FontContext, font_style: ::StyleArc<style_structs::Font>)
+pub fn font_metrics_for_style(font_context: &mut FontContext, font_style: ::ServoArc<style_structs::Font>)
                               -> FontMetrics {
     let fontgroup = font_context.layout_font_group_for_style(font_style);
     // FIXME(https://github.com/rust-lang/rust/issues/23338)
     let font = fontgroup.fonts[0].borrow();
     font.metrics.clone()
 }
 
 /// Returns the line block-size needed by the given computed style and font size.
--- a/servo/components/layout_thread/Cargo.toml
+++ b/servo/components/layout_thread/Cargo.toml
@@ -29,14 +29,15 @@ parking_lot = {version = "0.4", features
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 rayon = "0.8"
 script = {path = "../script"}
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = { path = "../selectors" }
 serde_json = "1.0"
+servo_arc = {path = "../servo_arc"}
 servo_atoms = {path = "../atoms"}
 servo_config = {path = "../config"}
 servo_geometry = {path = "../geometry"}
 servo_url = {path = "../url"}
 style = {path = "../style"}
 webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/layout_thread/dom_wrapper.rs
+++ b/servo/components/layout_thread/dom_wrapper.rs
@@ -49,16 +49,17 @@ use script::layout_exports::PendingResty
 use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
 use script_layout_interface::{OpaqueStyleAndLayoutData, StyleData};
 use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
 use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
 use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
 use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, RelevantLinkStatus};
 use selectors::matching::VisitedHandlingMode;
 use selectors::sink::Push;
+use servo_arc::{Arc, ArcBorrow};
 use servo_atoms::Atom;
 use servo_url::ServoUrl;
 use std::fmt;
 use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem::transmute;
 use std::sync::atomic::Ordering;
@@ -73,17 +74,16 @@ use style::dom::{DescendantsBit, DirtyDe
 use style::dom::{PresentationalHintsSynthesizer, TElement, TNode, UnsafeNode};
 use style::element_state::*;
 use style::font_metrics::ServoMetricsProvider;
 use style::properties::{ComputedValues, PropertyDeclarationBlock};
 use style::selector_parser::{AttrValue as SelectorAttrValue, NonTSPseudoClass, PseudoClassStringArg};
 use style::selector_parser::{PseudoElement, SelectorImpl, extended_filtering};
 use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
 use style::str::is_whitespace;
-use style::stylearc::{Arc, ArcBorrow};
 
 pub unsafe fn drop_style_and_layout_data(data: OpaqueStyleAndLayoutData) {
     let ptr: *mut StyleData = data.ptr.get();
     let non_opaque: *mut StyleAndLayoutData = ptr as *mut _;
     let _ = Box::from_raw(non_opaque);
 }
 
 #[derive(Copy, Clone)]
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -34,16 +34,17 @@ extern crate parking_lot;
 extern crate profile_traits;
 extern crate range;
 extern crate rayon;
 extern crate script;
 extern crate script_layout_interface;
 extern crate script_traits;
 extern crate selectors;
 extern crate serde_json;
+extern crate servo_arc;
 extern crate servo_atoms;
 extern crate servo_config;
 extern crate servo_geometry;
 extern crate servo_url;
 extern crate style;
 extern crate webrender_api;
 
 mod dom_wrapper;
@@ -92,16 +93,17 @@ use profile_traits::time::{TimerMetadata
 use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType};
 use script_layout_interface::message::{ScriptReflow, ReflowComplete};
 use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowResponse, OffsetParentResponse};
 use script_layout_interface::rpc::TextIndexResponse;
 use script_layout_interface::wrapper_traits::LayoutNode;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
 use script_traits::{ScrollState, UntrustedNodeAddress};
 use selectors::Element;
+use servo_arc::Arc as ServoArc;
 use servo_atoms::Atom;
 use servo_config::opts;
 use servo_config::prefs::PREFS;
 use servo_config::resource_files::read_resource_file;
 use servo_geometry::max_rect;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::cell::{Cell, RefCell};
@@ -122,17 +124,16 @@ use style::dom::{ShowSubtree, ShowSubtre
 use style::error_reporting::{NullReporter, RustLogReporter};
 use style::invalidation::element::restyle_hints::RestyleHint;
 use style::logical_geometry::LogicalPoint;
 use style::media_queries::{Device, MediaList, MediaType};
 use style::properties::PropertyId;
 use style::selector_parser::SnapshotMap;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW};
 use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards};
-use style::stylearc::Arc as StyleArc;
 use style::stylesheets::{Origin, Stylesheet, StylesheetInDocument, UserAgentStylesheets};
 use style::stylist::{ExtraStyleData, Stylist};
 use style::thread_state;
 use style::timer::Timer;
 use style::traversal::{DomTraversal, TraversalDriver, TraversalFlags};
 
 /// Information needed by the layout thread.
 pub struct LayoutThread {
@@ -206,20 +207,20 @@ pub struct LayoutThread {
 
     /// The root of the flow tree.
     root_flow: RefCell<Option<FlowRef>>,
 
     /// The document-specific shared lock used for author-origin stylesheets
     document_shared_lock: Option<SharedRwLock>,
 
     /// The list of currently-running animations.
-    running_animations: StyleArc<RwLock<FnvHashMap<OpaqueNode, Vec<Animation>>>>,
+    running_animations: ServoArc<RwLock<FnvHashMap<OpaqueNode, Vec<Animation>>>>,
 
     /// The list of animations that have expired since the last style recalculation.
-    expired_animations: StyleArc<RwLock<FnvHashMap<OpaqueNode, Vec<Animation>>>>,
+    expired_animations: ServoArc<RwLock<FnvHashMap<OpaqueNode, Vec<Animation>>>>,
 
     /// A counter for epoch messages
     epoch: Cell<Epoch>,
 
     /// The size of the viewport. This may be different from the size of the screen due to viewport
     /// constraints.
     viewport_size: Size2D<Au>,
 
@@ -421,17 +422,17 @@ fn add_font_face_rules(stylesheet: &Styl
                                               effective_sources,
                                               (*font_cache_sender).clone());
             }
         })
     }
 }
 
 #[derive(Clone)]
-struct StylesheetIterator<'a>(slice::Iter<'a, StyleArc<Stylesheet>>);
+struct StylesheetIterator<'a>(slice::Iter<'a, ServoArc<Stylesheet>>);
 
 impl<'a> Iterator for StylesheetIterator<'a> {
     type Item = &'a Stylesheet;
 
     fn next(&mut self) -> Option<Self::Item> {
         self.0.next().map(|s| &**s)
     }
 }
@@ -510,18 +511,18 @@ impl LayoutThread {
             parallel_traversal: parallel_traversal,
             parallel_flag: true,
             generation: Cell::new(0),
             new_animations_sender: new_animations_sender,
             new_animations_receiver: new_animations_receiver,
             outstanding_web_fonts: outstanding_web_fonts_counter,
             root_flow: RefCell::new(None),
             document_shared_lock: None,
-            running_animations: StyleArc::new(RwLock::new(FnvHashMap::default())),
-            expired_animations: StyleArc::new(RwLock::new(FnvHashMap::default())),
+            running_animations: ServoArc::new(RwLock::new(FnvHashMap::default())),
+            expired_animations: ServoArc::new(RwLock::new(FnvHashMap::default())),
             epoch: Cell::new(Epoch(0)),
             viewport_size: Size2D::new(Au(0), Au(0)),
             webrender_api: webrender_api_sender.create_api(),
             stylist: stylist,
             rw_data: Arc::new(Mutex::new(
                 LayoutThreadData {
                     constellation_chan: constellation_chan,
                     display_list: None,
@@ -820,17 +821,17 @@ impl LayoutThread {
         // rule nodes.  The `Stylist` checks when it is dropped that all rule
         // nodes have been GCed, so we want drop anyone who holds them first.
         self.root_flow.borrow_mut().take();
         // Drop the rayon threadpool if present.
         let _ = self.parallel_traversal.take();
     }
 
     fn handle_add_stylesheet<'a, 'b>(&self,
-                                     stylesheet: StyleArc<Stylesheet>,
+                                     stylesheet: ServoArc<Stylesheet>,
                                      possibly_locked_rw_data: &mut RwData<'a, 'b>) {
         // Find all font-face rules and notify the font cache of them.
         // GWTODO: Need to handle unloading web fonts.
 
         let rw_data = possibly_locked_rw_data.lock();
         let guard = stylesheet.shared_lock.read();
         if stylesheet.is_effective_for_device(self.stylist.device(), &guard) {
             add_font_face_rules(&*stylesheet,
--- a/servo/components/script/Cargo.toml
+++ b/servo/components/script/Cargo.toml
@@ -69,16 +69,17 @@ profile_traits = {path = "../profile_tra
 ref_filter_map = "1.0.1"
 ref_slice = "1.0"
 regex = "0.2"
 script_layout_interface = {path = "../script_layout_interface"}
 script_plugins = {path = "../script_plugins"}
 script_traits = {path = "../script_traits"}
 selectors = { path = "../selectors" }
 serde = "1.0"
+servo_arc = {path = "../servo_arc"}
 servo_atoms = {path = "../atoms"}
 servo_config = {path = "../config"}
 servo_geometry = {path = "../geometry" }
 servo_rand = {path = "../rand"}
 servo_url = {path = "../url"}
 smallvec = "0.4"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
--- a/servo/components/script/dom/bindings/trace.rs
+++ b/servo/components/script/dom/bindings/trace.rs
@@ -72,16 +72,17 @@ use profile_traits::mem::ProfilerChan as
 use profile_traits::time::ProfilerChan as TimeProfilerChan;
 use script_layout_interface::OpaqueStyleAndLayoutData;
 use script_layout_interface::reporter::CSSErrorReporter;
 use script_layout_interface::rpc::LayoutRPC;
 use script_traits::{DocumentActivity, TimerEventId, TimerSource, TouchpadPressurePhase};
 use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType};
 use selectors::matching::ElementSelectorFlags;
 use serde::{Deserialize, Serialize};
+use servo_arc::Arc as ServoArc;
 use servo_atoms::Atom;
 use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
 use smallvec::SmallVec;
 use std::cell::{Cell, RefCell, UnsafeCell};
 use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
 use std::hash::{BuildHasher, Hash};
 use std::ops::{Deref, DerefMut};
 use std::path::PathBuf;
@@ -92,17 +93,16 @@ use std::sync::mpsc::{Receiver, Sender};
 use std::time::{SystemTime, Instant};
 use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
 use style::context::QuirksMode;
 use style::element_state::*;
 use style::media_queries::MediaList;
 use style::properties::PropertyDeclarationBlock;
 use style::selector_parser::{PseudoElement, Snapshot};
 use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
-use style::stylearc::Arc as StyleArc;
 use style::stylesheets::{CssRules, FontFaceRule, KeyframesRule, MediaRule};
 use style::stylesheets::{NamespaceRule, StyleRule, ImportRule, SupportsRule, ViewportRule};
 use style::stylesheets::keyframes_rule::Keyframe;
 use style::values::specified::Length;
 use time::Duration;
 use uuid::Uuid;
 use webrender_api::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId};
 use webrender_api::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId, WebGLVertexArrayId};
@@ -160,17 +160,17 @@ unsafe impl<T: JSTraceable> JSTraceable 
 }
 
 unsafe impl<T: JSTraceable> JSTraceable for Arc<T> {
     unsafe fn trace(&self, trc: *mut JSTracer) {
         (**self).trace(trc)
     }
 }
 
-unsafe impl<T: JSTraceable> JSTraceable for StyleArc<T> {
+unsafe impl<T: JSTraceable> JSTraceable for ServoArc<T> {
     unsafe fn trace(&self, trc: *mut JSTracer) {
         (**self).trace(trc)
     }
 }
 
 unsafe impl<T: JSTraceable + ?Sized> JSTraceable for Box<T> {
     unsafe fn trace(&self, trc: *mut JSTracer) {
         (**self).trace(trc)
--- a/servo/components/script/dom/cssconditionrule.rs
+++ b/servo/components/script/dom/cssconditionrule.rs
@@ -5,18 +5,18 @@
 use dom::bindings::codegen::Bindings::CSSConditionRuleBinding::CSSConditionRuleMethods;
 use dom::bindings::inheritance::Castable;
 use dom::bindings::str::DOMString;
 use dom::cssgroupingrule::CSSGroupingRule;
 use dom::cssmediarule::CSSMediaRule;
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::csssupportsrule::CSSSupportsRule;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::shared_lock::{SharedRwLock, Locked};
-use style::stylearc::Arc;
 use style::stylesheets::CssRules as StyleCssRules;
 
 #[dom_struct]
 pub struct CSSConditionRule {
     cssgroupingrule: CSSGroupingRule,
 }
 
 impl CSSConditionRule {
--- a/servo/components/script/dom/cssfontfacerule.rs
+++ b/servo/components/script/dom/cssfontfacerule.rs
@@ -5,18 +5,18 @@
 use dom::bindings::codegen::Bindings::CSSFontFaceRuleBinding;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::shared_lock::{Locked, ToCssWithGuard};
-use style::stylearc::Arc;
 use style::stylesheets::FontFaceRule;
 
 #[dom_struct]
 pub struct CSSFontFaceRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
     fontfacerule: Arc<Locked<FontFaceRule>>,
 }
--- a/servo/components/script/dom/cssgroupingrule.rs
+++ b/servo/components/script/dom/cssgroupingrule.rs
@@ -7,18 +7,18 @@ use dom::bindings::error::{ErrorResult, 
 use dom::bindings::inheritance::Castable;
 use dom::bindings::js::{MutNullableJS, Root};
 use dom::bindings::reflector::DomObject;
 use dom::bindings::str::DOMString;
 use dom::cssrule::CSSRule;
 use dom::cssrulelist::{CSSRuleList, RulesSource};
 use dom::cssstylesheet::CSSStyleSheet;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::shared_lock::{SharedRwLock, Locked};
-use style::stylearc::Arc;
 use style::stylesheets::CssRules as StyleCssRules;
 
 #[dom_struct]
 pub struct CSSGroupingRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
     rules: Arc<Locked<StyleCssRules>>,
     rulelist: MutNullableJS<CSSRuleList>,
--- a/servo/components/script/dom/cssimportrule.rs
+++ b/servo/components/script/dom/cssimportrule.rs
@@ -5,18 +5,18 @@
 use dom::bindings::codegen::Bindings::CSSImportRuleBinding;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::shared_lock::{Locked, ToCssWithGuard};
-use style::stylearc::Arc;
 use style::stylesheets::ImportRule;
 
 #[dom_struct]
 pub struct CSSImportRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
     import_rule: Arc<Locked<ImportRule>>,
 }
--- a/servo/components/script/dom/csskeyframerule.rs
+++ b/servo/components/script/dom/csskeyframerule.rs
@@ -7,18 +7,18 @@ use dom::bindings::inheritance::Castable
 use dom::bindings::js::{JS, MutNullableJS, Root};
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::shared_lock::{Locked, ToCssWithGuard};
-use style::stylearc::Arc;
 use style::stylesheets::keyframes_rule::Keyframe;
 
 #[dom_struct]
 pub struct CSSKeyframeRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
     keyframerule: Arc<Locked<Keyframe>>,
     style_decl: MutNullableJS<CSSStyleDeclaration>,
--- a/servo/components/script/dom/csskeyframesrule.rs
+++ b/servo/components/script/dom/csskeyframesrule.rs
@@ -11,18 +11,18 @@ use dom::bindings::js::{MutNullableJS, R
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::csskeyframerule::CSSKeyframeRule;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 use dom::cssrulelist::{CSSRuleList, RulesSource};
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::shared_lock::{Locked, ToCssWithGuard};
-use style::stylearc::Arc;
 use style::stylesheets::keyframes_rule::{KeyframesRule, Keyframe, KeyframeSelector};
 use style::values::KeyframesName;
 
 #[dom_struct]
 pub struct CSSKeyframesRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
     keyframesrule: Arc<Locked<KeyframesRule>>,
--- a/servo/components/script/dom/cssmediarule.rs
+++ b/servo/components/script/dom/cssmediarule.rs
@@ -10,20 +10,20 @@ use dom::bindings::js::{MutNullableJS, R
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssconditionrule::CSSConditionRule;
 use dom::cssrule::SpecificCSSRule;
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::medialist::MediaList;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::media_queries::parse_media_query_list;
 use style::parser::ParserContext;
 use style::shared_lock::{Locked, ToCssWithGuard};
-use style::stylearc::Arc;
 use style::stylesheets::{CssRuleType, MediaRule};
 use style_traits::{PARSING_MODE_DEFAULT, ToCss};
 
 #[dom_struct]
 pub struct CSSMediaRule {
     cssconditionrule: CSSConditionRule,
     #[ignore_heap_size_of = "Arc"]
     mediarule: Arc<Locked<MediaRule>>,
--- a/servo/components/script/dom/cssnamespacerule.rs
+++ b/servo/components/script/dom/cssnamespacerule.rs
@@ -6,18 +6,18 @@ use dom::bindings::codegen::Bindings::CS
 use dom::bindings::codegen::Bindings::CSSNamespaceRuleBinding::CSSNamespaceRuleMethods;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::shared_lock::{Locked, ToCssWithGuard};
-use style::stylearc::Arc;
 use style::stylesheets::NamespaceRule;
 
 #[dom_struct]
 pub struct CSSNamespaceRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
     namespacerule: Arc<Locked<NamespaceRule>>,
 }
--- a/servo/components/script/dom/cssrulelist.rs
+++ b/servo/components/script/dom/cssrulelist.rs
@@ -8,18 +8,18 @@ use dom::bindings::codegen::Bindings::CS
 use dom::bindings::error::{Error, ErrorResult, Fallible};
 use dom::bindings::js::{JS, MutNullableJS, Root};
 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
 use dom::csskeyframerule::CSSKeyframeRule;
 use dom::cssrule::CSSRule;
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::shared_lock::Locked;
-use style::stylearc::Arc;
 use style::stylesheets::{CssRules, CssRulesHelpers, KeyframesRule, RulesMutateError};
 
 #[allow(unsafe_code)]
 unsafe_no_jsmanaged_fields!(RulesSource);
 
 unsafe_no_jsmanaged_fields!(CssRules);
 
 impl From<RulesMutateError> for Error {
--- a/servo/components/script/dom/cssstyledeclaration.rs
+++ b/servo/components/script/dom/cssstyledeclaration.rs
@@ -9,24 +9,24 @@ use dom::bindings::inheritance::Castable
 use dom::bindings::js::{JS, Root};
 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssrule::CSSRule;
 use dom::element::Element;
 use dom::node::{Node, window_from_node, document_from_node};
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use servo_url::ServoUrl;
 use std::ascii::AsciiExt;
 use style::attr::AttrValue;
 use style::properties::{Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId};
 use style::properties::{parse_one_declaration_into, parse_style_attribute, SourcePropertyDeclaration};
 use style::selector_parser::PseudoElement;
 use style::shared_lock::Locked;
-use style::stylearc::Arc;
 use style_traits::{PARSING_MODE_DEFAULT, ToCss};
 
 // http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
 #[dom_struct]
 pub struct CSSStyleDeclaration {
     reflector_: Reflector,
     owner: CSSStyleOwner,
     readonly: bool,
--- a/servo/components/script/dom/cssstylerule.rs
+++ b/servo/components/script/dom/cssstylerule.rs
@@ -11,20 +11,20 @@ use dom::bindings::js::{JS, MutNullableJ
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
 use selectors::parser::SelectorList;
+use servo_arc::Arc;
 use std::mem;
 use style::selector_parser::SelectorParser;
 use style::shared_lock::{Locked, ToCssWithGuard};
-use style::stylearc::Arc;
 use style::stylesheets::{StyleRule, Origin};
 
 #[dom_struct]
 pub struct CSSStyleRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
     stylerule: Arc<Locked<StyleRule>>,
     style_decl: MutNullableJS<CSSStyleDeclaration>,
--- a/servo/components/script/dom/cssstylesheet.rs
+++ b/servo/components/script/dom/cssstylesheet.rs
@@ -9,19 +9,19 @@ use dom::bindings::error::{Error, ErrorR
 use dom::bindings::js::{JS, MutNullableJS, Root};
 use dom::bindings::reflector::{reflect_dom_object, DomObject};
 use dom::bindings::str::DOMString;
 use dom::cssrulelist::{CSSRuleList, RulesSource};
 use dom::element::Element;
 use dom::stylesheet::StyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use std::cell::Cell;
 use style::shared_lock::SharedRwLock;
-use style::stylearc::Arc;
 use style::stylesheets::Stylesheet as StyleStyleSheet;
 
 #[dom_struct]
 pub struct CSSStyleSheet {
     stylesheet: StyleSheet,
     owner: JS<Element>,
     rulelist: MutNullableJS<CSSRuleList>,
     #[ignore_heap_size_of = "Arc"]
--- a/servo/components/script/dom/csssupportsrule.rs
+++ b/servo/components/script/dom/csssupportsrule.rs
@@ -8,19 +8,19 @@ use dom::bindings::codegen::Bindings::Wi
 use dom::bindings::js::Root;
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssconditionrule::CSSConditionRule;
 use dom::cssrule::SpecificCSSRule;
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::parser::ParserContext;
 use style::shared_lock::{Locked, ToCssWithGuard};
-use style::stylearc::Arc;
 use style::stylesheets::{CssRuleType, SupportsRule};
 use style::stylesheets::supports_rule::SupportsCondition;
 use style_traits::{PARSING_MODE_DEFAULT, ToCss};
 
 #[dom_struct]
 pub struct CSSSupportsRule {
     cssconditionrule: CSSConditionRule,
     #[ignore_heap_size_of = "Arc"]
--- a/servo/components/script/dom/cssviewportrule.rs
+++ b/servo/components/script/dom/cssviewportrule.rs
@@ -5,18 +5,18 @@
 use dom::bindings::codegen::Bindings::CSSViewportRuleBinding;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 use dom::cssrule::{CSSRule, SpecificCSSRule};
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::shared_lock::{Locked, ToCssWithGuard};
-use style::stylearc::Arc;
 use style::stylesheets::ViewportRule;
 
 #[dom_struct]
 pub struct CSSViewportRule {
     cssrule: CSSRule,
     #[ignore_heap_size_of = "Arc"]
     viewportrule: Arc<Locked<ViewportRule>>,
 }
--- a/servo/components/script/dom/document.rs
+++ b/servo/components/script/dom/document.rs
@@ -113,16 +113,17 @@ use num_traits::ToPrimitive;
 use script_layout_interface::message::{Msg, ReflowQueryType};
 use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
 use script_thread::{MainThreadScriptMsg, Runnable, ScriptThread};
 use script_traits::{AnimationState, CompositorEvent, DocumentActivity};
 use script_traits::{MouseButton, MouseEventType, MozBrowserEvent};
 use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TouchpadPressurePhase};
 use script_traits::{TouchEventType, TouchId};
 use script_traits::UntrustedNodeAddress;
+use servo_arc::Arc;
 use servo_atoms::Atom;
 use servo_config::prefs::PREFS;
 use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::cell::{Cell, Ref, RefMut};
 use std::collections::{HashMap, HashSet, VecDeque};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
@@ -132,17 +133,16 @@ use std::mem;
 use std::rc::Rc;
 use std::time::{Duration, Instant};
 use style::attr::AttrValue;
 use style::context::{QuirksMode, ReflowGoal};
 use style::invalidation::element::restyle_hints::{RestyleHint, RESTYLE_SELF, RESTYLE_STYLE_ATTRIBUTE};
 use style::selector_parser::{RestyleDamage, Snapshot};
 use style::shared_lock::SharedRwLock as StyleSharedRwLock;
 use style::str::{HTML_SPACE_CHARACTERS, split_html_space_chars, str_join};
-use style::stylearc::Arc;
 use style::stylesheets::Stylesheet;
 use task_source::TaskSource;
 use time;
 use timers::OneshotTimerCallback;
 use url::Host;
 use url::percent_encoding::percent_decode;
 use webrender_api::ClipId;
 
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -88,16 +88,17 @@ use net_traits::request::CorsSettings;
 use ref_filter_map::ref_filter_map;
 use script_layout_interface::message::ReflowQueryType;
 use script_thread::{Runnable, ScriptThread};
 use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
 use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, MatchingMode};
 use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
 use selectors::matching::{RelevantLinkStatus, matches_selector_list};
 use selectors::sink::Push;
+use servo_arc::Arc;
 use servo_atoms::Atom;
 use std::ascii::AsciiExt;
 use std::borrow::Cow;
 use std::cell::{Cell, Ref};
 use std::convert::TryFrom;
 use std::default::Default;
 use std::fmt;
 use std::rc::Rc;
@@ -108,17 +109,16 @@ use style::context::{QuirksMode, ReflowG
 use style::element_state::*;
 use style::invalidation::element::restyle_hints::RESTYLE_SELF;
 use style::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
 use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size, overflow_x};
 use style::rule_tree::CascadeLevel;
 use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
 use style::selector_parser::extended_filtering;
 use style::shared_lock::{SharedRwLock, Locked};
-use style::stylearc::Arc;
 use style::thread_state;
 use style::values::{CSSFloat, Either};
 use style::values::{specified, computed};
 use stylesheet_loader::StylesheetOwner;
 
 // TODO: Update focus state when the top-level browsing context gains or loses system focus,
 // and when the element enters or leaves a browsing context container.
 // https://html.spec.whatwg.org/multipage/#selector-focus
--- a/servo/components/script/dom/htmllinkelement.rs
+++ b/servo/components/script/dom/htmllinkelement.rs
@@ -21,25 +21,25 @@ use dom::htmlelement::HTMLElement;
 use dom::node::{Node, UnbindContext, document_from_node, window_from_node};
 use dom::stylesheet::StyleSheet as DOMStyleSheet;
 use dom::virtualmethods::VirtualMethods;
 use dom_struct::dom_struct;
 use html5ever::{LocalName, Prefix};
 use net_traits::ReferrerPolicy;
 use script_layout_interface::message::Msg;
 use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg};
+use servo_arc::Arc;
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use std::default::Default;
 use style::attr::AttrValue;
 use style::media_queries::parse_media_query_list;
 use style::parser::ParserContext as CssParserContext;
 use style::str::HTML_SPACE_CHARACTERS;
-use style::stylearc::Arc;
 use style::stylesheets::{CssRuleType, Stylesheet};
 use style_traits::PARSING_MODE_DEFAULT;
 use stylesheet_loader::{StylesheetLoader, StylesheetContextSource, StylesheetOwner};
 
 unsafe_no_jsmanaged_fields!(Stylesheet);
 
 #[derive(JSTraceable, PartialEq, Clone, Copy, HeapSizeOf)]
 pub struct RequestGenerationId(u32);
--- a/servo/components/script/dom/htmlmetaelement.rs
+++ b/servo/components/script/dom/htmlmetaelement.rs
@@ -15,23 +15,23 @@ use dom::document::Document;
 use dom::element::{AttributeMutation, Element};
 use dom::htmlelement::HTMLElement;
 use dom::htmlheadelement::HTMLHeadElement;
 use dom::node::{Node, UnbindContext, document_from_node, window_from_node};
 use dom::virtualmethods::VirtualMethods;
 use dom_struct::dom_struct;
 use html5ever::{LocalName, Prefix};
 use parking_lot::RwLock;
+use servo_arc::Arc;
 use servo_config::prefs::PREFS;
 use std::ascii::AsciiExt;
 use std::sync::atomic::AtomicBool;
 use style::attr::AttrValue;
 use style::media_queries::MediaList;
 use style::str::HTML_SPACE_CHARACTERS;
-use style::stylearc::Arc;
 use style::stylesheets::{Stylesheet, StylesheetContents, CssRule, CssRules, Origin, ViewportRule};
 
 #[dom_struct]
 pub struct HTMLMetaElement {
     htmlelement: HTMLElement,
     #[ignore_heap_size_of = "Arc"]
     stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
     cssom_stylesheet: MutNullableJS<CSSStyleSheet>,
--- a/servo/components/script/dom/htmlobjectelement.rs
+++ b/servo/components/script/dom/htmlobjectelement.rs
@@ -15,18 +15,18 @@ use dom::htmlelement::HTMLElement;
 use dom::htmlformelement::{FormControl, HTMLFormElement};
 use dom::node::{Node, window_from_node};
 use dom::validation::Validatable;
 use dom::validitystate::{ValidityState, ValidationFlags};
 use dom::virtualmethods::VirtualMethods;
 use dom_struct::dom_struct;
 use html5ever::{LocalName, Prefix};
 use net_traits::image::base::Image;
+use servo_arc::Arc;
 use std::default::Default;
-use style::stylearc::Arc;
 
 #[dom_struct]
 pub struct HTMLObjectElement {
     htmlelement: HTMLElement,
     #[ignore_heap_size_of = "Arc"]
     image: DOMRefCell<Option<Arc<Image>>>,
     form_owner: MutNullableJS<HTMLFormElement>,
 }
--- a/servo/components/script/dom/htmlstyleelement.rs
+++ b/servo/components/script/dom/htmlstyleelement.rs
@@ -16,20 +16,20 @@ use dom::eventtarget::EventTarget;
 use dom::htmlelement::HTMLElement;
 use dom::node::{ChildrenMutation, Node, UnbindContext, document_from_node, window_from_node};
 use dom::stylesheet::StyleSheet as DOMStyleSheet;
 use dom::virtualmethods::VirtualMethods;
 use dom_struct::dom_struct;
 use html5ever::{LocalName, Prefix};
 use net_traits::ReferrerPolicy;
 use script_layout_interface::message::Msg;
+use servo_arc::Arc;
 use std::cell::Cell;
 use style::media_queries::parse_media_query_list;
 use style::parser::ParserContext as CssParserContext;
-use style::stylearc::Arc;
 use style::stylesheets::{CssRuleType, Stylesheet, Origin};
 use style_traits::PARSING_MODE_DEFAULT;
 use stylesheet_loader::{StylesheetLoader, StylesheetOwner};
 
 #[dom_struct]
 pub struct HTMLStyleElement {
     htmlelement: HTMLElement,
     #[ignore_heap_size_of = "Arc"]
--- a/servo/components/script/dom/medialist.rs
+++ b/servo/components/script/dom/medialist.rs
@@ -7,21 +7,21 @@ use dom::bindings::codegen::Bindings::Me
 use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods;
 use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
 use dom::bindings::js::{JS, Root};
 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use servo_arc::Arc;
 use style::media_queries::{MediaQuery, parse_media_query_list};
 use style::media_queries::MediaList as StyleMediaList;
 use style::parser::ParserContext;
 use style::shared_lock::{SharedRwLock, Locked};
-use style::stylearc::Arc;
 use style::stylesheets::CssRuleType;
 use style_traits::{PARSING_MODE_DEFAULT, ToCss};
 
 #[dom_struct]
 pub struct MediaList {
     reflector_: Reflector,
     parent_stylesheet: JS<CSSStyleSheet>,
     #[ignore_heap_size_of = "Arc"]
--- a/servo/components/script/dom/node.rs
+++ b/servo/components/script/dom/node.rs
@@ -67,28 +67,28 @@ use ref_slice::ref_slice;
 use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData};
 use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress};
 use script_layout_interface::message::Msg;
 use script_thread::ScriptThread;
 use script_traits::DocumentActivity;
 use script_traits::UntrustedNodeAddress;
 use selectors::matching::{matches_selector_list, MatchingContext, MatchingMode};
 use selectors::parser::SelectorList;
+use servo_arc::Arc;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::cell::{Cell, UnsafeCell, RefMut};
 use std::cmp::max;
 use std::default::Default;
 use std::iter;
 use std::mem;
 use std::ops::Range;
 use style::context::QuirksMode;
 use style::dom::OpaqueNode;
 use style::selector_parser::{SelectorImpl, SelectorParser};
-use style::stylearc::Arc;
 use style::stylesheets::Stylesheet;
 use style::thread_state;
 use uuid::Uuid;
 
 //
 // The basic Node structure
 //
 
--- a/servo/components/script/dom/servoparser/html.rs
+++ b/servo/components/script/dom/servoparser/html.rs
@@ -9,24 +9,24 @@ use dom::bindings::inheritance::{Castabl
 use dom::bindings::js::{JS, Root};
 use dom::bindings::trace::JSTraceable;
 use dom::characterdata::CharacterData;
 use dom::document::Document;
 use dom::documenttype::DocumentType;
 use dom::element::Element;
 use dom::htmlscriptelement::HTMLScriptElement;
 use dom::htmltemplateelement::HTMLTemplateElement;
-use dom::node::{Node, TreeIterator};
+use dom::node::Node;
 use dom::processinginstruction::ProcessingInstruction;
 use dom::servoparser::Sink;
 use html5ever::QualName;
 use html5ever::buffer_queue::BufferQueue;
 use html5ever::serialize::{AttrRef, Serialize, Serializer};
 use html5ever::serialize::TraversalScope;
-use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
+use html5ever::serialize::TraversalScope::ChildrenOnly;
 use html5ever::tokenizer::{Tokenizer as HtmlTokenizer, TokenizerOpts, TokenizerResult};
 use html5ever::tree_builder::{Tracer as HtmlTracer, TreeBuilder, TreeBuilderOpts};
 use js::jsapi::JSTracer;
 use servo_url::ServoUrl;
 use std::io;
 
 #[derive(HeapSizeOf, JSTraceable)]
 #[must_root]
--- a/servo/components/script/lib.rs
+++ b/servo/components/script/lib.rs
@@ -78,16 +78,17 @@ extern crate phf;
 extern crate profile_traits;
 extern crate ref_filter_map;
 extern crate ref_slice;
 extern crate regex;
 extern crate script_layout_interface;
 extern crate script_traits;
 extern crate selectors;
 extern crate serde;
+extern crate servo_arc;
 #[macro_use] extern crate servo_atoms;
 extern crate servo_config;
 extern crate servo_geometry;
 extern crate servo_rand;
 extern crate servo_url;
 extern crate smallvec;
 #[macro_use]
 extern crate style;
--- a/servo/components/script/stylesheet_loader.rs
+++ b/servo/components/script/stylesheet_loader.rs
@@ -19,24 +19,24 @@ use hyper::header::ContentType;
 use hyper::mime::{Mime, TopLevel, SubLevel};
 use hyper_serde::Serde;
 use ipc_channel::ipc;
 use ipc_channel::router::ROUTER;
 use net_traits::{FetchResponseListener, FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy};
 use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType};
 use network_listener::{NetworkListener, PreInvoke};
 use parking_lot::RwLock;
+use servo_arc::Arc;
 use servo_url::ServoUrl;
 use std::mem;
 use std::sync::Mutex;
 use std::sync::atomic::AtomicBool;
 use style::media_queries::MediaList;
 use style::parser::ParserContext;
 use style::shared_lock::{Locked, SharedRwLock};
-use style::stylearc::Arc;
 use style::stylesheets::{CssRules, ImportRule, Namespaces, Stylesheet, StylesheetContents, Origin};
 use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
 use style::stylesheets::import_rule::ImportSheet;
 use style::values::specified::url::SpecifiedUrl;
 
 pub trait StylesheetOwner {
     /// Returns whether this element was inserted by the parser (i.e., it should
     /// trigger a document-load-blocking load).
--- a/servo/components/script_layout_interface/Cargo.toml
+++ b/servo/components/script_layout_interface/Cargo.toml
@@ -23,12 +23,13 @@ ipc-channel = "0.8"
 libc = "0.2"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 script_traits = {path = "../script_traits"}
 selectors = { path = "../selectors" }
+servo_arc = {path = "../servo_arc"}
 servo_atoms = {path = "../atoms"}
 servo_url = {path = "../url"}
 style = {path = "../style"}
 webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/script_layout_interface/lib.rs
+++ b/servo/components/script_layout_interface/lib.rs
@@ -25,16 +25,17 @@ extern crate libc;
 #[macro_use]
 extern crate log;
 extern crate msg;
 extern crate net_traits;
 extern crate profile_traits;
 extern crate range;
 extern crate script_traits;
 extern crate selectors;
+extern crate servo_arc;
 extern crate servo_atoms;
 extern crate servo_url;
 extern crate style;
 extern crate webrender_api;
 
 pub mod message;
 pub mod reporter;
 pub mod rpc;
--- a/servo/components/script_layout_interface/message.rs
+++ b/servo/components/script_layout_interface/message.rs
@@ -9,29 +9,30 @@ use gfx_traits::Epoch;
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
 use msg::constellation_msg::PipelineId;
 use net_traits::image_cache::ImageCache;
 use profile_traits::mem::ReportsChan;
 use rpc::LayoutRPC;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
 use script_traits::{ScrollState, UntrustedNodeAddress, WindowSizeData};
 use script_traits::Painter;
+use servo_arc::Arc as ServoArc;
 use servo_atoms::Atom;
 use servo_url::ServoUrl;
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender};
 use style::context::{QuirksMode, ReflowGoal};
 use style::properties::PropertyId;
 use style::selector_parser::PseudoElement;
 use style::stylesheets::Stylesheet;
 
 /// Asynchronous messages that script can send to layout.
 pub enum Msg {
     /// Adds the given stylesheet to the document.
-    AddStylesheet(::style::stylearc::Arc<Stylesheet>),
+    AddStylesheet(ServoArc<Stylesheet>),
 
     /// Change the quirks mode.
     SetQuirksMode(QuirksMode),
 
     /// Requests a reflow.
     Reflow(ScriptReflow),
 
     /// Get an RPC interface.
@@ -128,17 +129,17 @@ pub struct ReflowComplete {
 
 /// Information needed for a script-initiated reflow.
 pub struct ScriptReflow {
     /// General reflow data.
     pub reflow_info: Reflow,
     /// The document node.
     pub document: TrustedNodeAddress,
     /// The document's list of stylesheets.
-    pub document_stylesheets: Vec<::style::stylearc::Arc<Stylesheet>>,
+    pub document_stylesheets: Vec<ServoArc<Stylesheet>>,
     /// Whether the document's stylesheets have changed since the last script reflow.
     pub stylesheets_changed: bool,
     /// The current window size.
     pub window_size: WindowSizeData,
     /// The channel that we send a notification to.
     pub script_join_chan: Sender<ReflowComplete>,
     /// The type of query if any to perform during this reflow.
     pub query_type: ReflowQueryType,
--- a/servo/components/script_layout_interface/wrapper_traits.rs
+++ b/servo/components/script_layout_interface/wrapper_traits.rs
@@ -8,28 +8,28 @@ use HTMLCanvasData;
 use LayoutNodeType;
 use OpaqueStyleAndLayoutData;
 use SVGSVGData;
 use atomic_refcell::AtomicRef;
 use gfx_traits::{ByteIndex, FragmentType, combine_id_with_fragment_type};
 use html5ever::{Namespace, LocalName};
 use msg::constellation_msg::{BrowsingContextId, PipelineId};
 use range::Range;
+use servo_arc::Arc;
 use servo_url::ServoUrl;
 use std::fmt::Debug;
 use style::attr::AttrValue;
 use style::computed_values::display;
 use style::context::SharedStyleContext;
 use style::data::ElementData;
 use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthesizer, TNode};
 use style::dom::OpaqueNode;
 use style::font_metrics::ServoMetricsProvider;
 use style::properties::{CascadeFlags, ComputedValues};
 use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
-use style::stylearc::Arc;
 use style::stylist::RuleInclusion;
 use webrender_api::ClipId;
 
 #[derive(Copy, PartialEq, Clone, Debug)]
 pub enum PseudoElementType<T> {
     Normal,
     Before(T),
     After(T),
--- a/servo/components/selectors/parser.rs
+++ b/servo/components/selectors/parser.rs
@@ -866,16 +866,33 @@ impl ToCss for Combinator {
             Combinator::PseudoElement => Ok(()),
         }
     }
 }
 
 impl<Impl: SelectorImpl> ToCss for Component<Impl> {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         use self::Component::*;
+
+        /// Serialize <an+b> values (part of the CSS Syntax spec, but currently only used here).
+        /// https://drafts.csswg.org/css-syntax-3/#serialize-an-anb-value
+        fn write_affine<W>(dest: &mut W, a: i32, b: i32) -> fmt::Result where W: fmt::Write {
+            match (a, b) {
+                (0, 0) => dest.write_char('0'),
+
+                (1, 0) => dest.write_char('n'),
+                (_, 0) => write!(dest, "{}n", a),
+
+                (0, _) => write!(dest, "{}", b),
+                (1, _) => write!(dest, "n{:+}", b),
+                (-1, _) => write!(dest, "-n{:+}", b),
+                (_, _) => write!(dest, "{}n{:+}", a, b),
+            }
+        }
+
         match *self {
             Combinator(ref c) => {
                 c.to_css(dest)
             }
             PseudoElement(ref p) => {
                 p.to_css(dest)
             }
             ID(ref s) => {
@@ -930,20 +947,27 @@ impl<Impl: SelectorImpl> ToCss for Compo
             FirstChild => dest.write_str(":first-child"),
             LastChild => dest.write_str(":last-child"),
             OnlyChild => dest.write_str(":only-child"),
             Root => dest.write_str(":root"),
             Empty => dest.write_str(":empty"),
             FirstOfType => dest.write_str(":first-of-type"),
             LastOfType => dest.write_str(":last-of-type"),
             OnlyOfType => dest.write_str(":only-of-type"),
-            NthChild(a, b) => write!(dest, ":nth-child({}n{:+})", a, b),
-            NthLastChild(a, b) => write!(dest, ":nth-last-child({}n{:+})", a, b),
-            NthOfType(a, b) => write!(dest, ":nth-of-type({}n{:+})", a, b),
-            NthLastOfType(a, b) => write!(dest, ":nth-last-of-type({}n{:+})", a, b),
+            NthChild(a, b) | NthLastChild(a, b) | NthOfType(a, b) | NthLastOfType(a, b) => {
+                match *self {
+                    NthChild(_, _) => dest.write_str(":nth-child(")?,
+                    NthLastChild(_, _) => dest.write_str(":nth-last-child(")?,
+                    NthOfType(_, _) => dest.write_str(":nth-of-type(")?,
+                    NthLastOfType(_, _) => dest.write_str(":nth-last-of-type(")?,
+                    _ => unreachable!(),
+                }
+                write_affine(dest, a, b)?;
+                dest.write_char(')')
+            }
             NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
         }
     }
 }
 
 impl<Impl: SelectorImpl> ToCss for AttrSelectorWithNamespace<Impl> {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         dest.write_char('[')?;
--- a/servo/components/style/Cargo.toml
+++ b/servo/components/style/Cargo.toml
@@ -55,18 +55,18 @@ num-integer = "0.1.32"
 num-traits = "0.1.32"
 ordered-float = "0.4"
 owning_ref = "0.3.3"
 parking_lot = "0.4"
 pdqsort = "0.1.0"
 precomputed-hash = "0.1"
 rayon = "0.8"
 selectors = { path = "../selectors" }
+serde = {version = "1.0", optional = true, features = ["derive"]}
 servo_arc = { path = "../servo_arc" }
-serde = {version = "1.0", optional = true, features = ["derive"]}
 servo_atoms = {path = "../atoms", optional = true}
 servo_config = {path = "../config", optional = true}
 smallvec = "0.4"
 style_derive = {path = "../style_derive"}
 style_traits = {path = "../style_traits"}
 servo_url = {path = "../url", optional = true}
 time = "0.1"
 unicode-bidi = "0.3"
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -4,26 +4,25 @@
 
 //! CSS transitions and animations.
 #![deny(missing_docs)]
 
 use Atom;
 use bezier::Bezier;
 use context::SharedStyleContext;
 use dom::OpaqueNode;
-use euclid::Point2D;
 use font_metrics::FontMetricsProvider;
 use properties::{self, CascadeFlags, ComputedValues, Importance};
 use properties::animated_properties::{AnimatableLonghand, AnimatedProperty, TransitionProperty};
 use properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
 use properties::longhands::animation_iteration_count::single_value::computed_value::T as AnimationIterationCount;
 use properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
 use rule_tree::CascadeLevel;
+use servo_arc::Arc;
 use std::sync::mpsc::Sender;
-use stylearc::Arc;
 use stylesheets::keyframes_rule::{KeyframesStep, KeyframesStepValue};
 use timer::Timer;
 use values::computed::Time;
 use values::computed::transform::TimingFunction;
 use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction};
 
 /// This structure represents a keyframes animation current iteration state.
 ///
@@ -364,28 +363,20 @@ impl PropertyAnimation {
             Some(property_animation)
         } else {
             None
         }
     }
 
     /// Update the given animation at a given point of progress.
     pub fn update(&self, style: &mut ComputedValues, time: f64) {
-        let solve_bezier = |(p1, p2): (Point2D<_>, Point2D<_>)| {
-            let epsilon = 1. / (200. * (self.duration.seconds() as f64));
-            let bezier = Bezier::new(
-                Point2D::new(p1.x as f64, p1.y as f64),
-                Point2D::new(p2.x as f64, p2.y as f64),
-            );
-            bezier.solve(time, epsilon)
-        };
-
+        let epsilon = 1. / (200. * (self.duration.seconds() as f64));
         let progress = match self.timing_function {
-            GenericTimingFunction::CubicBezier(p1, p2) => {
-                solve_bezier((p1, p2))
+            GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => {
+                Bezier::new(x1, y1, x2, y2).solve(time, epsilon)
             },
             GenericTimingFunction::Steps(steps, StepPosition::Start) => {
                 (time * (steps as f64)).ceil() / (steps as f64)
             },
             GenericTimingFunction::Steps(steps, StepPosition::End) => {
                 (time * (steps as f64)).floor() / (steps as f64)
             },
             GenericTimingFunction::Frames(frames) => {
@@ -400,17 +391,18 @@ impl PropertyAnimation {
                     // However, this solution is still not correct because |time| is possible
                     // outside the range of [0, 1] after introducing Web Animations. We should fix
                     // this problem when implementing web animations.
                     out = 1.0;
                 }
                 out
             },
             GenericTimingFunction::Keyword(keyword) => {
-                solve_bezier(keyword.to_bezier_points())
+                let (x1, x2, y1, y2) = keyword.to_bezier();
+                Bezier::new(x1, x2, y1, y2).solve(time, epsilon)
             },
         };
 
         self.property.update(style, progress);
     }
 
     #[inline]
     fn does_animate(&self) -> bool {
--- a/servo/components/style/applicable_declarations.rs
+++ b/servo/components/style/applicable_declarations.rs
@@ -1,21 +1,21 @@
 /* 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/. */
 
 //! Applicable declarations management.
 
 use properties::PropertyDeclarationBlock;
 use rule_tree::{CascadeLevel, StyleSource};
+use servo_arc::Arc;
 use shared_lock::Locked;
 use smallvec::SmallVec;
 use std::fmt::{Debug, self};
 use std::mem;
-use stylearc::Arc;
 
 /// List of applicable declarations. This is a transient structure that shuttles
 /// declarations between selector matching and inserting into the rule tree, and
 /// therefore we want to avoid heap-allocation where possible.
 ///
 /// In measurements on wikipedia, we pretty much never have more than 8 applicable
 /// declarations, so we could consider making this 8 entries instead of 16.
 /// However, it may depend a lot on workload, and stack space is cheap.
--- a/servo/components/style/attr.rs
+++ b/servo/components/style/attr.rs
@@ -8,24 +8,24 @@
 
 use {Atom, Prefix, Namespace, LocalName};
 use app_units::Au;
 use cssparser::{self, Color, RGBA};
 use euclid::num::Zero;
 use num_traits::ToPrimitive;
 use properties::PropertyDeclarationBlock;
 use selectors::attr::AttrSelectorOperation;
+use servo_arc::Arc;
 use servo_url::ServoUrl;
 use shared_lock::Locked;
 use std::ascii::AsciiExt;
 use std::str::FromStr;
 use str::{HTML_SPACE_CHARACTERS, read_exponent, read_fraction};
 use str::{read_numbers, split_commas, split_html_space_chars};
 use str::str_join;
-use stylearc::Arc;
 use values::specified::Length;
 
 // Duplicated from script::dom::values.
 const UNSIGNED_LONG_MAX: u32 = 2147483647;
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum LengthOrPercentageOrAuto {
--- a/servo/components/style/bezier.rs
+++ b/servo/components/style/bezier.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Parametric Bézier curves.
 //!
 //! This is based on `WebCore/platform/graphics/UnitBezier.h` in WebKit.
 
 #![deny(missing_docs)]
 
-use euclid::Point2D;
+use values::CSSFloat;
 
 const NEWTON_METHOD_ITERATIONS: u8 = 8;
 
 /// A unit cubic Bézier curve, used for timing functions in CSS transitions and animations.
 pub struct Bezier {
     ax: f64,
     bx: f64,
     cx: f64,
@@ -26,22 +26,22 @@ impl Bezier {
     /// Create a unit cubic Bézier curve from the two middle control points.
     ///
     /// X coordinate is time, Y coordinate is function advancement.
     /// The nominal range for both is 0 to 1.
     ///
     /// The start and end points are always (0, 0) and (1, 1) so that a transition or animation
     /// starts at 0% and ends at 100%.
     #[inline]
-    pub fn new(p1: Point2D<f64>, p2: Point2D<f64>) -> Bezier {
-        let cx = 3.0 * p1.x;
-        let bx = 3.0 * (p2.x - p1.x) - cx;
+    pub fn new(x1: CSSFloat, y1: CSSFloat, x2: CSSFloat, y2: CSSFloat) -> Bezier {
+        let cx = 3. * x1 as f64;
+        let bx = 3. * (x2 as f64 - x1 as f64) - cx;
 
-        let cy = 3.0 * p1.y;
-        let by = 3.0 * (p2.y - p1.y) - cy;
+        let cy = 3. * y1 as f64;
+        let by = 3. * (y2 as f64 - y1 as f64) - cy;
 
         Bezier {
             ax: 1.0 - cx - bx,
             bx: bx,
             cx: cx,
             ay: 1.0 - cy - by,
             by: by,
             cy: cy,
--- a/servo/components/style/bloom.rs
+++ b/servo/components/style/bloom.rs
@@ -6,18 +6,18 @@
 //! descendant selectors.
 
 #![deny(missing_docs)]
 
 use atomic_refcell::{AtomicRefMut, AtomicRefCell};
 use dom::{SendElement, TElement};
 use owning_ref::OwningHandle;
 use selectors::bloom::BloomFilter;
+use servo_arc::Arc;
 use smallvec::SmallVec;
-use stylearc::Arc;
 
 /// Bloom filters are large allocations, so we store them in thread-local storage
 /// such that they can be reused across style traversals. StyleBloom is responsible
 /// for ensuring that the bloom filter is zeroed when it is dropped.
 thread_local!(static BLOOM_KEY: Arc<AtomicRefCell<BloomFilter>> =
               Arc::new(AtomicRefCell::new(BloomFilter::new())));
 
 /// A struct that allows us to fast-reject deep descendant selectors avoiding
--- a/servo/components/style/context.rs
+++ b/servo/components/style/context.rs
@@ -15,23 +15,23 @@ use euclid::Size2D;
 use fnv::FnvHashMap;
 use font_metrics::FontMetricsProvider;
 #[cfg(feature = "gecko")] use gecko_bindings::structs;
 #[cfg(feature = "servo")] use parking_lot::RwLock;
 use properties::ComputedValues;
 use rule_tree::StrongRuleNode;
 use selector_parser::{EAGER_PSEUDO_COUNT, SnapshotMap};
 use selectors::matching::ElementSelectorFlags;
+use servo_arc::Arc;
 use shared_lock::StylesheetGuards;
 use sharing::StyleSharingCandidateCache;
 use std::fmt;
 use std::ops;
 #[cfg(feature = "servo")] use std::sync::Mutex;
 #[cfg(feature = "servo")] use std::sync::mpsc::Sender;
-use stylearc::Arc;
 use stylist::Stylist;
 use thread_state;
 use time;
 use timer::Timer;
 use traversal::{DomTraversal, TraversalFlags};
 
 pub use selectors::matching::QuirksMode;
 
--- a/servo/components/style/custom_properties.rs
+++ b/servo/components/style/custom_properties.rs
@@ -6,22 +6,22 @@
 //!
 //! [custom]: https://drafts.csswg.org/css-variables/
 
 use Atom;
 use cssparser::{Delimiter, Parser, ParserInput, SourcePosition, Token, TokenSerializationType};
 use parser::ParserContext;
 use properties::{CSSWideKeyword, DeclaredValue};
 use selectors::parser::SelectorParseError;
+use servo_arc::Arc;
 use std::ascii::AsciiExt;
 use std::borrow::Cow;
 use std::collections::{HashMap, hash_map, HashSet};
 use std::fmt;
 use style_traits::{HasViewportPercentage, ToCss, StyleParseError, ParseError};
-use stylearc::Arc;
 
 /// A custom property name is just an `Atom`.
 ///
 /// Note that this does not include the `--` prefix
 pub type Name = Atom;
 
 /// Parse a custom property name.
 ///
--- a/servo/components/style/data.rs
+++ b/servo/components/style/data.rs
@@ -6,19 +6,19 @@
 
 use context::SharedStyleContext;
 use dom::TElement;
 use invalidation::element::restyle_hints::RestyleHint;
 use properties::ComputedValues;
 use properties::longhands::display::computed_value as display;
 use rule_tree::StrongRuleNode;
 use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
+use servo_arc::Arc;
 use shared_lock::StylesheetGuards;
 use std::ops::{Deref, DerefMut};
-use stylearc::Arc;
 
 bitflags! {
     flags RestyleFlags: u8 {
         /// Whether the styles changed for this restyle.
         const WAS_RESTYLED = 1 << 0,
         /// Whether we reframed/reconstructed any ancestor or self.
         const ANCESTOR_WAS_RECONSTRUCTED = 1 << 1,
     }
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -18,24 +18,24 @@ use media_queries::Device;
 use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
 #[cfg(feature = "gecko")] use properties::animated_properties::AnimationValue;
 #[cfg(feature = "gecko")] use properties::animated_properties::TransitionProperty;
 use rule_tree::CascadeLevel;
 use selector_parser::{AttrValue, ElementExt, PreExistingComputedValues};
 use selector_parser::{PseudoClassStringArg, PseudoElement};
 use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
 use selectors::sink::Push;
+use servo_arc::{Arc, ArcBorrow};
 use shared_lock::Locked;
 use smallvec::VecLike;
 use std::fmt;
 #[cfg(feature = "gecko")] use std::collections::HashMap;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::Deref;
-use stylearc::{Arc, ArcBorrow};
 use stylist::Stylist;
 use thread_state;
 use traversal::TraversalFlags;
 
 pub use style_traits::UnsafeNode;
 
 /// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed
 /// back into a non-opaque representation. The only safe operation that can be
--- a/servo/components/style/encoding_support.rs
+++ b/servo/components/style/encoding_support.rs
@@ -6,19 +6,19 @@
 
 extern crate encoding;
 
 use context::QuirksMode;
 use cssparser::{stylesheet_encoding, EncodingSupport};
 use error_reporting::ParseErrorReporter;
 use media_queries::MediaList;
 use self::encoding::{EncodingRef, DecoderTrap};
+use servo_arc::Arc;
 use shared_lock::SharedRwLock;
 use std::str;
-use stylearc::Arc;
 use stylesheets::{Stylesheet, StylesheetLoader, Origin, UrlExtraData};
 
 struct RustEncoding;
 
 impl EncodingSupport for RustEncoding {
     type Encoding = EncodingRef;
 
     fn utf8() -> Self::Encoding {
--- a/servo/components/style/gecko/data.rs
+++ b/servo/components/style/gecko/data.rs
@@ -12,18 +12,18 @@ use gecko::rules::{CounterStyleRule, Fon
 use gecko_bindings::bindings::{self, RawServoStyleSet};
 use gecko_bindings::structs::{ServoStyleSheet, StyleSheetInfo, ServoStyleSheetInner};
 use gecko_bindings::structs::RawGeckoPresContextOwned;
 use gecko_bindings::structs::nsIDocument;
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
 use invalidation::media_queries::{MediaListKey, ToMediaListKey};
 use media_queries::{Device, MediaList};
 use properties::ComputedValues;
+use servo_arc::Arc;
 use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
-use stylearc::Arc;
 use stylesheet_set::StylesheetSet;
 use stylesheets::{Origin, StylesheetContents, StylesheetInDocument};
 use stylist::{ExtraStyleData, Stylist};
 
 /// Little wrapper to a Gecko style sheet.
 #[derive(PartialEq, Eq, Debug)]
 pub struct GeckoStyleSheet(*const ServoStyleSheet);
 
--- a/servo/components/style/gecko/restyle_damage.rs
+++ b/servo/components/style/gecko/restyle_damage.rs
@@ -4,18 +4,18 @@
 
 //! Gecko's restyle damage computation (aka change hints, aka `nsChangeHint`).
 
 use gecko_bindings::bindings;
 use gecko_bindings::structs;
 use gecko_bindings::structs::{nsChangeHint, nsStyleContext};
 use matching::{StyleChange, StyleDifference};
 use properties::ComputedValues;
+use servo_arc::Arc;
 use std::ops::{BitAnd, BitOr, BitOrAssign, Not};
-use stylearc::Arc;
 
 /// The representation of Gecko's restyle damage is just a wrapper over
 /// `nsChangeHint`.
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub struct GeckoRestyleDamage(nsChangeHint);
 
 impl GeckoRestyleDamage {
     /// Trivially construct a new `GeckoRestyleDamage`.
--- a/servo/components/style/gecko/url.rs
+++ b/servo/components/style/gecko/url.rs
@@ -5,19 +5,19 @@
 //! Common handling for the specified value CSS url() values.
 
 use gecko_bindings::structs::{ServoBundledURI, URLExtraData};
 use gecko_bindings::structs::mozilla::css::URLValueData;
 use gecko_bindings::structs::root::mozilla::css::ImageValue;
 use gecko_bindings::structs::root::nsStyleImageRequest;
 use gecko_bindings::sugar::refptr::RefPtr;
 use parser::ParserContext;
+use servo_arc::Arc;
 use std::fmt;
 use style_traits::{ToCss, ParseError};
-use stylearc::Arc;
 
 /// A specified url() value for gecko. Gecko does not eagerly resolve SpecifiedUrls.
 #[derive(Clone, Debug, PartialEq)]
 pub struct SpecifiedUrl {
     /// The URL in unresolved string form.
     ///
     /// Refcounted since cloning this should be cheap and data: uris can be
     /// really large.
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -74,26 +74,26 @@ use properties::animated_properties::Tra
 use properties::style_structs::Font;
 use rule_tree::CascadeLevel as ServoCascadeLevel;
 use selector_parser::{AttrValue, ElementExt, PseudoClassStringArg};
 use selectors::Element;
 use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
 use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext};
 use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode};
 use selectors::sink::Push;
+use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
 use shared_lock::Locked;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::ops::DerefMut;
 use std::ptr;
 use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
-use stylearc::{Arc, ArcBorrow, RawOffsetArc};
 use stylesheets::UrlExtraData;
 use stylist::Stylist;
 
 /// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
 ///
 /// Important: We don't currently refcount the DOM, because the wrapper lifetime
 /// magic guarantees that our LayoutFoo references won't outlive the root, and
 /// we don't mutate any of the references on the Gecko side during restyle.
--- a/servo/components/style/gecko_bindings/sugar/ns_timing_function.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_timing_function.rs
@@ -1,13 +1,12 @@
 /* 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 euclid::{Point2D, TypedPoint2D};
 use gecko_bindings::structs::{nsTimingFunction, nsTimingFunction_Type};
 use std::mem;
 use values::computed::ToComputedValue;
 use values::computed::transform::TimingFunction as ComputedTimingFunction;
 use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction, TimingKeyword};
 use values::specified::transform::TimingFunction;
 
 impl nsTimingFunction {
@@ -23,28 +22,29 @@ impl nsTimingFunction {
 
     fn set_as_frames(&mut self, frames: u32) {
         self.mType = nsTimingFunction_Type::Frames;
         unsafe {
             self.__bindgen_anon_1.__bindgen_anon_1.as_mut().mStepsOrFrames = frames;
         }
     }
 
-    fn set_as_bezier(&mut self,
-                     function_type: nsTimingFunction_Type,
-                     p1: Point2D<f32>,
-                     p2: Point2D<f32>) {
+    fn set_as_bezier(
+        &mut self,
+        function_type: nsTimingFunction_Type,
+        x1: f32, y1: f32, x2: f32, y2: f32,
+    ) {
         self.mType = function_type;
         unsafe {
             let ref mut gecko_cubic_bezier =
                 unsafe { self.__bindgen_anon_1.mFunc.as_mut() };
-            gecko_cubic_bezier.mX1 = p1.x;
-            gecko_cubic_bezier.mY1 = p1.y;
-            gecko_cubic_bezier.mX2 = p2.x;
-            gecko_cubic_bezier.mY2 = p2.y;
+            gecko_cubic_bezier.mX1 = x1;
+            gecko_cubic_bezier.mY1 = y1;
+            gecko_cubic_bezier.mX2 = x2;
+            gecko_cubic_bezier.mY2 = y2;
         }
     }
 }
 
 impl From<ComputedTimingFunction> for nsTimingFunction {
     fn from(function: ComputedTimingFunction) -> nsTimingFunction {
         TimingFunction::from_computed_value(&function).into()
     }
@@ -62,24 +62,25 @@ impl From<TimingFunction> for nsTimingFu
             GenericTimingFunction::Steps(steps, StepPosition::End) => {
                 debug_assert!(steps.value() >= 0);
                 tf.set_as_step(nsTimingFunction_Type::StepEnd, steps.value() as u32);
             },
             GenericTimingFunction::Frames(frames) => {
                 debug_assert!(frames.value() >= 2);
                 tf.set_as_frames(frames.value() as u32);
             },
-            GenericTimingFunction::CubicBezier(p1, p2) => {
-                tf.set_as_bezier(nsTimingFunction_Type::CubicBezier,
-                                 Point2D::new(p1.x.get(), p1.y.get()),
-                                 Point2D::new(p2.x.get(), p2.y.get()));
+            GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => {
+                tf.set_as_bezier(
+                    nsTimingFunction_Type::CubicBezier,
+                    x1.get(), y1.get(), x2.get(), y2.get(),
+                );
             },
             GenericTimingFunction::Keyword(keyword) => {
-                let (p1, p2) = keyword.to_bezier_points();
-                tf.set_as_bezier(keyword.into(), p1, p2)
+                let (x1, y1, x2, y2) = keyword.to_bezier();
+                tf.set_as_bezier(keyword.into(), x1, y1, x2, y2);
             },
         }
         tf
     }
 }
 
 impl From<nsTimingFunction> for ComputedTimingFunction {
     fn from(function: nsTimingFunction) -> ComputedTimingFunction {
@@ -109,21 +110,24 @@ impl From<nsTimingFunction> for Computed
             },
             nsTimingFunction_Type::EaseOut => {
                 GenericTimingFunction::Keyword(TimingKeyword::EaseOut)
             },
             nsTimingFunction_Type::EaseInOut => {
                 GenericTimingFunction::Keyword(TimingKeyword::EaseInOut)
             },
             nsTimingFunction_Type::CubicBezier => {
-                GenericTimingFunction::CubicBezier(
-                    TypedPoint2D::new(unsafe { function.__bindgen_anon_1.mFunc.as_ref().mX1 },
-                                      unsafe { function.__bindgen_anon_1.mFunc.as_ref().mY1 }),
-                    TypedPoint2D::new(unsafe { function.__bindgen_anon_1.mFunc.as_ref().mX2 },
-                                      unsafe { function.__bindgen_anon_1.mFunc.as_ref().mY2 }))
+                unsafe {
+                    GenericTimingFunction::CubicBezier {
+                        x1: function.__bindgen_anon_1.mFunc.as_ref().mX1,
+                        y1: function.__bindgen_anon_1.mFunc.as_ref().mY1,
+                        x2: function.__bindgen_anon_1.mFunc.as_ref().mX2,
+                        y2: function.__bindgen_anon_1.mFunc.as_ref().mY2,
+                    }
+                }
             },
         }
     }
 }
 
 impl From<TimingKeyword> for nsTimingFunction_Type {
     fn from(keyword: TimingKeyword) -> Self {
         match keyword {
--- a/servo/components/style/gecko_bindings/sugar/ownership.rs
+++ b/servo/components/style/gecko_bindings/sugar/ownership.rs
@@ -1,19 +1,19 @@
 /* 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/. */
 
 //! Helpers for different FFI pointer kinds that Gecko's FFI layer uses.
 
+use servo_arc::{Arc, RawOffsetArc};
 use std::marker::PhantomData;
 use std::mem::{forget, transmute};
 use std::ops::{Deref, DerefMut};
 use std::ptr;
-use stylearc::{Arc, RawOffsetArc};
 
 /// Indicates that a given Servo type has a corresponding Gecko FFI type.
 pub unsafe trait HasFFI : Sized + 'static {
     /// The corresponding Gecko type that this rust type represents.
     ///
     /// See the examples in `components/style/gecko/conversions.rs`.
     type FFIType: Sized;
 }
--- a/servo/components/style/gecko_bindings/sugar/refptr.rs
+++ b/servo/components/style/gecko_bindings/sugar/refptr.rs
@@ -1,20 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! A rust helper to ease the use of Gecko's refcounted types.
 
 use gecko_bindings::structs;
 use gecko_bindings::sugar::ownership::HasArcFFI;
+use servo_arc::Arc;
 use std::{mem, ptr};
 use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
-use stylearc::Arc;
 
 /// Trait for all objects that have Addref() and Release
 /// methods and can be placed inside RefPtr<T>
 pub unsafe trait RefCounted {
     /// Bump the reference count.
     fn addref(&self);
     /// Decrease the reference count.
     unsafe fn release(&self);
--- a/servo/components/style/invalidation/element/invalidator.rs
+++ b/servo/components/style/invalidation/element/invalidator.rs
@@ -261,22 +261,20 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator
         let result = self.invalidate_child(
             child,
             invalidations,
             &mut sibling_invalidations
         );
 
         // Roots of NAC subtrees can indeed generate sibling invalidations, but
         // they can be just ignored, since they have no siblings.
-        debug_assert!(child.implemented_pseudo_element().is_none() ||
-                      sibling_invalidations.is_empty(),
-                      "pseudos can't generate sibling invalidations, since \
-                      using them in other position that isn't the \
-                      rightmost part of the selector is invalid \
-                      (for now at least)");
+        //
+        // Note that we can end up testing selectors that wouldn't end up
+        // matching due to this being NAC, like those coming from document
+        // rules, but we overinvalidate instead of checking this.
 
         result
     }
 
     /// Invalidate a child and recurse down invalidating its descendants if
     /// needed.
     fn invalidate_child(
         &mut self,
--- a/servo/components/style/macros.rs
+++ b/servo/components/style/macros.rs
@@ -107,10 +107,15 @@ macro_rules! define_keyword_type {
                              -> Result<$name, ::style_traits::ParseError<'i>> {
                 input.expect_ident_matching($css).map(|_| $name).map_err(|e| e.into())
             }
         }
 
         impl $crate::values::computed::ComputedValueAsSpecified for $name {}
         impl $crate::values::animated::AnimatedValueAsComputed for $name {}
         no_viewport_percentage!($name);
+
+        impl $crate::values::animated::ToAnimatedZero for $name {
+            #[inline]
+            fn to_animated_zero(&self) -> Result<Self, ()> { Ok($name) }
+        }
     };
 }
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -13,17 +13,17 @@ use dom::TElement;
 use invalidation::element::restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS};
 use invalidation::element::restyle_hints::{RESTYLE_SMIL, RESTYLE_STYLE_ATTRIBUTE};
 use invalidation::element::restyle_hints::RestyleHint;
 use properties::ComputedValues;
 use properties::longhands::display::computed_value as display;
 use rule_tree::{CascadeLevel, StrongRuleNode};
 use selector_parser::{PseudoElement, RestyleDamage};
 use selectors::matching::ElementSelectorFlags;
-use stylearc::{Arc, ArcBorrow};
+use servo_arc::{Arc, ArcBorrow};
 
 /// Represents the result of comparing an element's old and new style.
 pub struct StyleDifference {
     /// The resulting damage.
     pub damage: RestyleDamage,
 
     /// Whether any styles changed.
     pub change: StyleChange,
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -53,19 +53,19 @@ use gecko::values::round_border_to_devic
 use logical_geometry::WritingMode;
 use media_queries::Device;
 use properties::animated_properties::TransitionProperty;
 use properties::computed_value_flags::ComputedValueFlags;
 use properties::{longhands, FontComputationData, Importance, LonghandId};
 use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId};
 use rule_tree::StrongRuleNode;
 use selector_parser::PseudoElement;
+use servo_arc::{Arc, RawOffsetArc};
 use std::mem::{forget, uninitialized, transmute, zeroed};
 use std::{cmp, ops, ptr};
-use stylearc::{Arc, RawOffsetArc};
 use values::{Auto, CustomIdent, Either, KeyframesName};
 use values::computed::ToComputedValue;
 use values::computed::effects::{BoxShadow, Filter, SimpleShadow};
 use values::computed::length::Percentage;
 use computed_values::border_style;
 
 pub mod style_structs {
     % for style_struct in data.style_structs:
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -124,16 +124,18 @@
                 pub Vec<single_value::T>,
                 % else:
                 pub SmallVec<[single_value::T; 1]>,
                 % endif
             );
 
             % if animation_value_type == "ComputedValue":
                 use properties::animated_properties::Animatable;
+                use values::animated::ToAnimatedZero;
+
                 impl Animatable for T {
                     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
                         -> Result<Self, ()> {
                         self.0.add_weighted(&other.0, self_portion, other_portion).map(T)
                     }
 
                     fn add(&self, other: &Self) -> Result<Self, ()> {
                         self.0.add(&other.0).map(T)
@@ -144,16 +146,21 @@
                         self.0.compute_distance(&other.0)
                     }
 
                     #[inline]
                     fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
                         self.0.compute_squared_distance(&other.0)
                     }
                 }
+
+                impl ToAnimatedZero for T {
+                    #[inline]
+                    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+                }
             % endif
 
             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>;
@@ -293,17 +300,17 @@
         use properties::{DeclaredValue, LonghandId, LonghandIdSet};
         #[allow(unused_imports)]
         use properties::{CSSWideKeyword, ComputedValues, PropertyDeclaration};
         #[allow(unused_imports)]
         use properties::style_structs;
         #[allow(unused_imports)]
         use selectors::parser::SelectorParseError;
         #[allow(unused_imports)]
-        use stylearc::Arc;
+        use servo_arc::Arc;
         #[allow(unused_imports)]
         use style_traits::{ParseError, StyleParseError};
         #[allow(unused_imports)]
         use values::computed::{Context, ToComputedValue};
         #[allow(unused_imports)]
         use values::{computed, generics, specified};
         #[allow(unused_imports)]
         use Atom;
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -28,30 +28,73 @@ use selectors::parser::SelectorParseErro
 use smallvec::SmallVec;
 use std::cmp;
 #[cfg(feature = "gecko")] use fnv::FnvHashMap;
 use style_traits::ParseError;
 use super::ComputedValues;
 #[cfg(any(feature = "gecko", feature = "testing"))]
 use values::Auto;
 use values::{CSSFloat, CustomIdent, Either};
-use values::animated::ToAnimatedValue;
+use values::animated::{ToAnimatedValue, ToAnimatedZero};
 use values::animated::effects::BoxShadowList as AnimatedBoxShadowList;
 use values::animated::effects::Filter as AnimatedFilter;
 use values::animated::effects::FilterList as AnimatedFilterList;
 use values::animated::effects::TextShadowList as AnimatedTextShadowList;
 use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
 use values::computed::{BorderCornerRadius, ClipRect};
 use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
 use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToComputedValue};
 use values::generics::{SVGPaint, SVGPaintKind};
 use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
 use values::generics::effects::Filter;
 use values::generics::position as generic_position;
 
+/// A trait used to implement various procedures used during animation.
+pub trait Animatable: Sized {
+    /// Performs a weighted sum of this value and |other|. This is used for
+    /// interpolation and addition of animation values.
+    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+        -> Result<Self, ()>;
+
+    /// [Interpolates][interpolation] a value with another for a given property.
+    ///
+    /// [interpolation]: https://w3c.github.io/web-animations/#animation-interpolation
+    fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
+        self.add_weighted(other, 1.0 - progress, progress)
+    }
+
+    /// Returns the [sum][animation-addition] of this value and |other|.
+    ///
+    /// [animation-addition]: https://w3c.github.io/web-animations/#animation-addition
+    fn add(&self, other: &Self) -> Result<Self, ()> {
+        self.add_weighted(other, 1.0, 1.0)
+    }
+
+    /// [Accumulates][animation-accumulation] this value onto itself (|count| - 1) times then
+    /// accumulates |other| onto the result.
+    /// If |count| is zero, the result will be |other|.
+    ///
+    /// [animation-accumulation]: https://w3c.github.io/web-animations/#animation-accumulation
+    fn accumulate(&self, other: &Self, count: u64) -> Result<Self, ()> {
+        self.add_weighted(other, count as f64, 1.0)
+    }
+
+    /// Compute distance between a value and another for a given property.
+    fn compute_distance(&self, _other: &Self) -> Result<f64, ()>  { Err(()) }
+
+    /// In order to compute the Euclidean distance of a list or property value with multiple
+    /// components, we need to compute squared distance for each element, so the vector can sum it
+    /// and then get its squared root as the distance.
+    fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
+        self.compute_distance(other).map(|d| d * d)
+    }
+}
+
+/// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list
+pub trait RepeatableListAnimatable: Animatable {}
 
 /// A longhand property whose animation type is not "none".
 ///
 /// NOTE: This includes the 'display' property since it is animatable from SMIL even though it is
 /// not animatable from CSS animations or Web Animations. CSS transitions also does not allow
 /// animating 'display', but for CSS transitions we have the separate TransitionProperty type.
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@@ -687,29 +730,16 @@ impl Animatable for AnimationValue {
             % endfor
             _ => {
                 panic!("Expected accumulation of computed values of the same \
                         property, got: {:?}, {:?}", self, other);
             }
         }
     }
 
-    fn get_zero_value(&self) -> Result<Self, ()> {
-        match *self {
-            % for prop in data.longhands:
-            % if prop.animatable and prop.animation_value_type != "discrete":
-            AnimationValue::${prop.camel_case}(ref base) => {
-                Ok(AnimationValue::${prop.camel_case}(base.get_zero_value()?))
-            },
-            % endif
-            % endfor
-            _ => Err(()),
-        }
-    }
-
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         match (self, other) {
             % for prop in data.longhands:
                 % if prop.animatable:
                     % if prop.animation_value_type != "discrete":
                         (&AnimationValue::${prop.camel_case}(ref from),
                          &AnimationValue::${prop.camel_case}(ref to)) => {
                             from.compute_distance(to)
@@ -725,71 +755,32 @@ impl Animatable for AnimationValue {
             _ => {
                 panic!("Expected compute_distance of computed values of the same \
                         property, got: {:?}, {:?}", self, other);
             }
         }
     }
 }
 
-
-/// A trait used to implement various procedures used during animation.
-pub trait Animatable: Sized {
-    /// Performs a weighted sum of this value and |other|. This is used for
-    /// interpolation and addition of animation values.
-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-        -> Result<Self, ()>;
-
-    /// [Interpolates][interpolation] a value with another for a given property.
-    ///
-    /// [interpolation]: https://w3c.github.io/web-animations/#animation-interpolation
-    fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
-        self.add_weighted(other, 1.0 - progress, progress)
-    }
-
-    /// Returns the [sum][animation-addition] of this value and |other|.
-    ///
-    /// [animation-addition]: https://w3c.github.io/web-animations/#animation-addition
-    fn add(&self, other: &Self) -> Result<Self, ()> {
-        self.add_weighted(other, 1.0, 1.0)
-    }
-
-    /// [Accumulates][animation-accumulation] this value onto itself (|count| - 1) times then
-    /// accumulates |other| onto the result.
-    /// If |count| is zero, the result will be |other|.
-    ///
-    /// [animation-accumulation]: https://w3c.github.io/web-animations/#animation-accumulation
-    fn accumulate(&self, other: &Self, count: u64) -> Result<Self, ()> {
-        self.add_weighted(other, count as f64, 1.0)
-    }
-
-    /// Returns a value that, when added with an underlying value, will produce the underlying
-    /// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
-    /// the zero value to the 'by' value, and then adds the result to the underlying value.
-    ///
-    /// This is not the necessarily the same as the initial value of a property. For example, the
-    /// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the
-    /// underlying value will not produce the underlying value.
+impl ToAnimatedZero for AnimationValue {
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> { Err(()) }
-
-    /// Compute distance between a value and another for a given property.
-    fn compute_distance(&self, _other: &Self) -> Result<f64, ()>  { Err(()) }
-
-    /// In order to compute the Euclidean distance of a list or property value with multiple
-    /// components, we need to compute squared distance for each element, so the vector can sum it
-    /// and then get its squared root as the distance.
-    fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
-        self.compute_distance(other).map(|d| d * d)
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        match *self {
+            % for prop in data.longhands:
+            % if prop.animatable and prop.animation_value_type != "discrete":
+            AnimationValue::${prop.camel_case}(ref base) => {
+                Ok(AnimationValue::${prop.camel_case}(base.to_animated_zero()?))
+            },
+            % endif
+            % endfor
+            _ => Err(()),
+        }
     }
 }
 
-/// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list
-pub trait RepeatableListAnimatable: Animatable {}
-
 impl RepeatableListAnimatable for LengthOrPercentage {}
 impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {}
 
 macro_rules! repeated_vec_impl {
     ($($ty:ty),*) => {
         $(impl<T: RepeatableListAnimatable> Animatable for $ty {
             fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
                 -> Result<Self, ()> {
@@ -830,19 +821,16 @@ repeated_vec_impl!(SmallVec<[T; 1]>, Vec
 /// https://drafts.csswg.org/css-transitions/#animtype-number
 impl Animatable for Au {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         Ok(Au((self.0 as f64 * self_portion + other.0 as f64 * other_portion).round() as i32))
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> { Ok(Au(0)) }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         self.0.compute_distance(&other.0)
     }
 }
 
 impl <T> Animatable for Option<T>
     where T: Animatable,
 {
@@ -883,51 +871,42 @@ impl <T> Animatable for Option<T>
 /// https://drafts.csswg.org/css-transitions/#animtype-number
 impl Animatable for f32 {
     #[inline]
     fn add_weighted(&self, other: &f32, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         Ok((*self as f64 * self_portion + *other as f64 * other_portion) as f32)
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> { Ok(0.) }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         Ok((*self - *other).abs() as f64)
     }
 }
 
 /// https://drafts.csswg.org/css-transitions/#animtype-number
 impl Animatable for f64 {
     #[inline]
     fn add_weighted(&self, other: &f64, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         Ok(*self * self_portion + *other * other_portion)
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> { Ok(0.) }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         Ok((*self - *other).abs())
     }
 }
 
 /// https://drafts.csswg.org/css-transitions/#animtype-integer
 impl Animatable for i32 {
     #[inline]
     fn add_weighted(&self, other: &i32, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         Ok((*self as f64 * self_portion + *other as f64 * other_portion).round() as i32)
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> { Ok(0) }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         Ok((*self - *other).abs() as f64)
     }
 }
 
 /// https://drafts.csswg.org/css-transitions/#animtype-number
 impl Animatable for Angle {
     #[inline]
@@ -952,24 +931,28 @@ impl Animatable for Angle {
 /// https://drafts.csswg.org/css-transitions/#animtype-percentage
 impl Animatable for Percentage {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         Ok(Percentage((self.0 as f64 * self_portion + other.0 as f64 * other_portion) as f32))
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> { Ok(Percentage(0.)) }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         Ok((self.0 as f64 - other.0 as f64).abs())
     }
 }
 
+impl ToAnimatedZero for Percentage {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        Ok(Percentage(0.))
+    }
+}
+
 /// https://drafts.csswg.org/css-transitions/#animtype-visibility
 impl Animatable for Visibility {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {
             (Visibility::visible, _) => {
                 Ok(if self_portion > 0.0 { *self } else { *other })
             },
@@ -985,16 +968,23 @@ impl Animatable for Visibility {
         if *self == *other {
             Ok(0.0)
         } else {
             Ok(1.0)
         }
     }
 }
 
+impl ToAnimatedZero for Visibility {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        Err(())
+    }
+}
+
 impl<T: Animatable + Copy> Animatable for Size2D<T> {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         let width = self.width.add_weighted(&other.width, self_portion, other_portion)?;
         let height = self.height.add_weighted(&other.height, self_portion, other_portion)?;
 
         Ok(Size2D::new(width, height))
     }
@@ -1023,16 +1013,21 @@ impl Animatable for BorderCornerRadius {
 
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
         Ok(self.0.width.compute_squared_distance(&other.0.width)? +
            self.0.height.compute_squared_distance(&other.0.height)?)
     }
 }
 
+impl ToAnimatedZero for BorderCornerRadius {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+}
+
 /// https://drafts.csswg.org/css-transitions/#animtype-length
 impl Animatable for VerticalAlign {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {
             (VerticalAlign::LengthOrPercentage(LengthOrPercentage::Length(ref this)),
              VerticalAlign::LengthOrPercentage(LengthOrPercentage::Length(ref other))) => {
                 this.add_weighted(other, self_portion, other_portion).map(|value| {
@@ -1050,16 +1045,21 @@ impl Animatable for VerticalAlign {
              VerticalAlign::LengthOrPercentage(ref other)) => {
                 this.compute_distance(other)
             },
             _ => Err(()),
         }
     }
 }
 
+impl ToAnimatedZero for VerticalAlign {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+}
+
 /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
 impl Animatable for CalcLengthOrPercentage {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         fn add_weighted_half<T>(this: Option<T>,
                                 other: Option<T>,
                                 self_portion: f64,
                                 other_portion: f64)
@@ -1121,21 +1121,16 @@ impl Animatable for LengthOrPercentage {
                 let other: CalcLengthOrPercentage = From::from(other);
                 this.add_weighted(&other, self_portion, other_portion)
                     .map(LengthOrPercentage::Calc)
             }
         }
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> {
-        Ok(LengthOrPercentage::zero())
-    }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         match (*self, *other) {
             (LengthOrPercentage::Length(ref this),
              LengthOrPercentage::Length(ref other)) => {
                 this.compute_distance(other)
             },
             (LengthOrPercentage::Percentage(ref this),
              LengthOrPercentage::Percentage(ref other)) => {
@@ -1168,16 +1163,23 @@ impl Animatable for LengthOrPercentage {
                 let length_diff = (this.unclamped_length().0 - other.unclamped_length().0) as f64;
                 let percentage_diff = (this.percentage() - other.percentage()) as f64;
                 Ok(length_diff * length_diff + percentage_diff * percentage_diff)
             }
         }
     }
 }
 
+impl ToAnimatedZero for LengthOrPercentage {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        Ok(LengthOrPercentage::zero())
+    }
+}
+
 /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
 impl Animatable for LengthOrPercentageOrAuto {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {
             (LengthOrPercentageOrAuto::Length(ref this),
              LengthOrPercentageOrAuto::Length(ref other)) => {
                 this.add_weighted(other, self_portion, other_portion)
@@ -1198,28 +1200,16 @@ impl Animatable for LengthOrPercentageOr
                     Ok(Some(result)) => Ok(LengthOrPercentageOrAuto::Calc(result)),
                     _ => Err(()),
                 }
             }
         }
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> {
-        match *self {
-            LengthOrPercentageOrAuto::Length(_) |
-            LengthOrPercentageOrAuto::Percentage(_) |
-            LengthOrPercentageOrAuto::Calc(_) => {
-                Ok(LengthOrPercentageOrAuto::Length(Au(0)))
-            },
-            LengthOrPercentageOrAuto::Auto => Err(()),
-        }
-    }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         match (*self, *other) {
             (LengthOrPercentageOrAuto::Length(ref this),
              LengthOrPercentageOrAuto::Length(ref other)) => {
                 this.compute_distance(other)
             },
             (LengthOrPercentageOrAuto::Percentage(ref this),
              LengthOrPercentageOrAuto::Percentage(ref other)) => {
@@ -1257,16 +1247,30 @@ impl Animatable for LengthOrPercentageOr
                 } else {
                     Err(())
                 }
             }
         }
     }
 }
 
+impl ToAnimatedZero for LengthOrPercentageOrAuto {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        match *self {
+            LengthOrPercentageOrAuto::Length(_) |
+            LengthOrPercentageOrAuto::Percentage(_) |
+            LengthOrPercentageOrAuto::Calc(_) => {
+                Ok(LengthOrPercentageOrAuto::Length(Au(0)))
+            },
+            LengthOrPercentageOrAuto::Auto => Err(()),
+        }
+    }
+}
+
 /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
 impl Animatable for LengthOrPercentageOrNone {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {
             (LengthOrPercentageOrNone::Length(ref this),
              LengthOrPercentageOrNone::Length(ref other)) => {
                 this.add_weighted(other, self_portion, other_portion)
@@ -1287,28 +1291,16 @@ impl Animatable for LengthOrPercentageOr
                     Ok(Some(result)) => Ok(LengthOrPercentageOrNone::Calc(result)),
                     _ => Err(()),
                 }
             },
         }
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> {
-        match *self {
-            LengthOrPercentageOrNone::Length(_) |
-            LengthOrPercentageOrNone::Percentage(_) |
-            LengthOrPercentageOrNone::Calc(_) => {
-                Ok(LengthOrPercentageOrNone::Length(Au(0)))
-            },
-            LengthOrPercentageOrNone::None => Err(()),
-        }
-    }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         match (*self, *other) {
             (LengthOrPercentageOrNone::Length(ref this),
              LengthOrPercentageOrNone::Length(ref other)) => {
                 this.compute_distance(other)
             },
             (LengthOrPercentageOrNone::Percentage(ref this),
              LengthOrPercentageOrNone::Percentage(ref other)) => {
@@ -1319,16 +1311,30 @@ impl Animatable for LengthOrPercentageOr
                 let this = <Option<CalcLengthOrPercentage>>::from(this);
                 let other = <Option<CalcLengthOrPercentage>>::from(other);
                 this.compute_distance(&other)
             },
         }
     }
 }
 
+impl ToAnimatedZero for LengthOrPercentageOrNone {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        match *self {
+            LengthOrPercentageOrNone::Length(_) |
+            LengthOrPercentageOrNone::Percentage(_) |
+            LengthOrPercentageOrNone::Calc(_) => {
+                Ok(LengthOrPercentageOrNone::Length(Au(0)))
+            },
+            LengthOrPercentageOrNone::None => Err(()),
+        }
+    }
+}
+
 /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
 impl Animatable for MozLength {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {
             (MozLength::LengthOrPercentageOrAuto(ref this),
              MozLength::LengthOrPercentageOrAuto(ref other)) => {
                 this.add_weighted(other, self_portion, other_portion)
@@ -1345,16 +1351,21 @@ impl Animatable for MozLength {
              MozLength::LengthOrPercentageOrAuto(ref other)) => {
                 this.compute_distance(other)
             },
             _ => Err(()),
         }
     }
 }
 
+impl ToAnimatedZero for MozLength {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+}
+
 /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
 impl Animatable for MaxLength {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {
             (MaxLength::LengthOrPercentageOrNone(ref this),
              MaxLength::LengthOrPercentageOrNone(ref other)) => {
                 this.add_weighted(other, self_portion, other_portion)
@@ -1371,39 +1382,48 @@ impl Animatable for MaxLength {
              MaxLength::LengthOrPercentageOrNone(ref other)) => {
                 this.compute_distance(other)
             },
             _ => Err(()),
         }
     }
 }
 
+impl ToAnimatedZero for MaxLength {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+}
+
 /// http://dev.w3.org/csswg/css-transitions/#animtype-font-weight
 impl Animatable for FontWeight {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         let a = self.0 as f64;
         let b = other.0 as f64;
         const NORMAL: f64 = 400.;
         let weight = (a - NORMAL) * self_portion + (b - NORMAL) * other_portion + NORMAL;
         let weight = (weight.min(100.).max(900.) / 100.).round() * 100.;
         Ok(FontWeight(weight as u16))
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> { Ok(FontWeight::normal()) }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         let a = self.0 as f64;
         let b = other.0 as f64;
         a.compute_distance(&b)
     }
 }
 
+impl ToAnimatedZero for FontWeight {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        Ok(FontWeight::normal())
+    }
+}
+
 /// https://drafts.csswg.org/css-fonts/#font-stretch-prop
 impl Animatable for FontStretch {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
         -> Result<Self, ()>
     {
         let from = f64::from(*self);
         let to = f64::from(*other);
@@ -1417,16 +1437,21 @@ impl Animatable for FontStretch {
     #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         let from = f64::from(*self);
         let to   = f64::from(*other);
         from.compute_distance(&to)
     }
 }
 
+impl ToAnimatedZero for FontStretch {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+}
+
 /// We should treat font stretch as real number in order to interpolate this property.
 /// https://drafts.csswg.org/css-fonts-3/#font-stretch-animation
 impl From<FontStretch> for f64 {
     fn from(stretch: FontStretch) -> f64 {
         use self::FontStretch::*;
         match stretch {
             ultra_condensed => 1.0,
             extra_condensed => 2.0,
@@ -1458,35 +1483,41 @@ impl<H: Animatable, V: Animatable> Anima
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         Ok(generic_position::Position {
             horizontal: self.horizontal.add_weighted(&other.horizontal, self_portion, other_portion)?,
             vertical: self.vertical.add_weighted(&other.vertical, self_portion, other_portion)?,
         })
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> {
-        Ok(generic_position::Position {
-            horizontal: self.horizontal.get_zero_value()?,
-            vertical: self.vertical.get_zero_value()?,
-        })
-    }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         self.compute_squared_distance(other).map(|sd| sd.sqrt())
     }
 
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
         Ok(self.horizontal.compute_squared_distance(&other.horizontal)? +
            self.vertical.compute_squared_distance(&other.vertical)?)
     }
 }
 
+impl<H, V> ToAnimatedZero for generic_position::Position<H, V>
+where
+    H: ToAnimatedZero,
+    V: ToAnimatedZero,
+{
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        Ok(generic_position::Position {
+            horizontal: self.horizontal.to_animated_zero()?,
+            vertical: self.vertical.to_animated_zero()?,
+        })
+    }
+}
+
 impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V>
     where H: RepeatableListAnimatable, V: RepeatableListAnimatable {}
 
 /// https://drafts.csswg.org/css-transitions/#animtype-rect
 impl Animatable for ClipRect {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
         -> Result<Self, ()> {
@@ -1510,16 +1541,21 @@ impl Animatable for ClipRect {
             self.right.compute_distance(&other.right)?,
             self.bottom.compute_distance(&other.bottom)?,
             self.left.compute_distance(&other.left)?
         ];
         Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff))
     }
 }
 
+impl ToAnimatedZero for ClipRect {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+}
+
 /// Check if it's possible to do a direct numerical interpolation
 /// between these two transform lists.
 /// http://dev.w3.org/csswg/css-transforms/#transform-transform-animation
 fn can_interpolate_list(from_list: &[TransformOperation],
                         to_list: &[TransformOperation]) -> bool {
     // Lists must be equal length
     if from_list.len() != to_list.len() {
         return false;
@@ -2584,19 +2620,23 @@ impl Animatable for TransformList {
                 // Hence the result is just |other|.
                 Ok(other.clone())
             }
             _ => {
                 Ok(TransformList(None))
             }
         }
     }
+}
 
+impl ToAnimatedZero for TransformList {
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> { Ok(TransformList(None)) }
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        Ok(TransformList(None))
+    }
 }
 
 impl<T, U> Animatable for Either<T, U>
         where T: Animatable + Copy, U: Animatable + Copy,
 {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {
@@ -2609,28 +2649,16 @@ impl<T, U> Animatable for Either<T, U>
             _ => {
                 let result = if self_portion > other_portion {*self} else {*other};
                 Ok(result)
             }
         }
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> {
-        match *self {
-            Either::First(ref this) => {
-                Ok(Either::First(this.get_zero_value()?))
-            },
-            Either::Second(ref this) => {
-                Ok(Either::Second(this.get_zero_value()?))
-            },
-        }
-    }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         match (self, other) {
             (&Either::First(ref this), &Either::First(ref other)) => {
                 this.compute_distance(other)
             },
             (&Either::Second(ref this), &Either::Second(ref other)) => {
                 this.compute_distance(other)
             },
@@ -2647,16 +2675,34 @@ impl<T, U> Animatable for Either<T, U>
             (&Either::Second(ref this), &Either::Second(ref other)) => {
                 this.compute_squared_distance(other)
             },
             _ => Err(())
         }
     }
 }
 
+impl<A, B> ToAnimatedZero for Either<A, B>
+where
+    A: ToAnimatedZero,
+    B: ToAnimatedZero,
+{
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        match *self {
+            Either::First(ref first) => {
+                Ok(Either::First(first.to_animated_zero()?))
+            },
+            Either::Second(ref second) => {
+                Ok(Either::Second(second.to_animated_zero()?))
+            },
+        }
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 /// Unlike RGBA, each component value may exceed the range [0.0, 1.0].
 pub struct IntermediateRGBA {
     /// The red component.
     pub red: f32,
     /// The green component.
     pub green: f32,
@@ -2726,21 +2772,16 @@ impl Animatable for IntermediateRGBA {
             let blue = (self.blue * self.alpha).add_weighted(
                 &(other.blue * other.alpha), self_portion, other_portion
             )? * 1. / alpha;
             Ok(IntermediateRGBA::new(red, green, blue, alpha))
         }
     }
 
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> {
-        Ok(IntermediateRGBA::transparent())
-    }
-
-    #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         self.compute_squared_distance(other).map(|sq| sq.sqrt())
     }
 
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
         let start = [ self.alpha,
                       self.red * self.alpha,
@@ -2754,16 +2795,23 @@ impl Animatable for IntermediateRGBA {
                                .fold(0.0f64, |n, (&a, &b)| {
                                    let diff = (a - b) as f64;
                                    n + diff * diff
                                });
         Ok(diff)
     }
 }
 
+impl ToAnimatedZero for IntermediateRGBA {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        Ok(IntermediateRGBA::transparent())
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 pub struct IntermediateColor {
     color: IntermediateRGBA,
     foreground_ratio: f32,
 }
 
@@ -2892,16 +2940,21 @@ impl Animatable for IntermediateColor {
             let other_color = other.effective_intermediate_rgba();
             let dist = self_color.compute_squared_distance(&other_color)?;
             let ratio_diff = (self.foreground_ratio - other.foreground_ratio) as f64;
             Ok(dist + ratio_diff * ratio_diff)
         }
     }
 }
 
+impl ToAnimatedZero for IntermediateColor {
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+}
+
 /// Animatable SVGPaint
 pub type IntermediateSVGPaint = SVGPaint<IntermediateRGBA>;
 
 /// Animatable SVGPaintKind
 pub type IntermediateSVGPaintKind = SVGPaintKind<IntermediateRGBA>;
 
 impl Animatable for IntermediateSVGPaint {
     #[inline]
@@ -2917,22 +2970,24 @@ impl Animatable for IntermediateSVGPaint
         self.compute_squared_distance(other).map(|sq| sq.sqrt())
     }
 
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
         Ok(self.kind.compute_squared_distance(&other.kind)? +
             self.fallback.compute_squared_distance(&other.fallback)?)
     }
+}
 
+impl ToAnimatedZero for IntermediateSVGPaint {
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> {
+    fn to_animated_zero(&self) -> Result<Self, ()> {
         Ok(IntermediateSVGPaint {
-            kind: self.kind.get_zero_value()?,
-            fallback: self.fallback.and_then(|v| v.get_zero_value().ok()),
+            kind: self.kind.to_animated_zero()?,
+            fallback: self.fallback.and_then(|v| v.to_animated_zero().ok()),
         })
     }
 }
 
 impl Animatable for IntermediateSVGPaintKind {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (self, other) {
@@ -2955,22 +3010,24 @@ impl Animatable for IntermediateSVGPaint
                 self_color.compute_distance(other_color)
             }
             (&SVGPaintKind::None, &SVGPaintKind::None) |
             (&SVGPaintKind::ContextFill, &SVGPaintKind::ContextFill) |
             (&SVGPaintKind::ContextStroke, &SVGPaintKind::ContextStroke)=> Ok(0.0),
             _ => Err(())
         }
     }
+}
 
+impl ToAnimatedZero for IntermediateSVGPaintKind {
     #[inline]
-    fn get_zero_value(&self) -> Result<Self, ()> {
+    fn to_animated_zero(&self) -> Result<Self, ()> {
         match *self {
             SVGPaintKind::Color(ref color) => {
-                Ok(SVGPaintKind::Color(color.get_zero_value()?))
+                Ok(SVGPaintKind::Color(color.to_animated_zero()?))
             },
             SVGPaintKind::None |
             SVGPaintKind::ContextFill |
             SVGPaintKind::ContextStroke => Ok(self.clone()),
             _ => Err(()),
         }
     }
 }
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -1039,16 +1039,17 @@ macro_rules! impl_gecko_keyword_conversi
                 None
             }
         }
     }
 
     pub mod computed_value {
         use properties::animated_properties::Animatable;
         use values::CSSFloat;
+        use values::animated::ToAnimatedZero;
 
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         #[derive(Copy, Clone, Debug, PartialEq, ToCss)]
         pub enum T {
             None,
             Number(CSSFloat),
         }
 
@@ -1076,16 +1077,21 @@ macro_rules! impl_gecko_keyword_conversi
             fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
                 match (*self, *other) {
                     (T::Number(ref number), T::Number(ref other)) =>
                         number.compute_distance(other),
                     _ => Err(()),
                 }
             }
         }
+
+        impl ToAnimatedZero for T {
+            #[inline]
+            fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+        }
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T::None
     }
 
     #[inline]
--- a/servo/components/style/properties/longhand/inherited_table.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_table.mako.rs
@@ -23,16 +23,17 @@
 <%helpers:longhand name="border-spacing" animation_value_type="ComputedValue" boxed="True"
                    spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing">
     use app_units::Au;
     use values::specified::{AllowQuirks, Length};
 
     pub mod computed_value {
         use app_units::Au;
         use properties::animated_properties::Animatable;
+        use values::animated::ToAnimatedZero;
 
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         #[derive(Clone, Copy, Debug, PartialEq, ToCss)]
         pub struct T {
             pub horizontal: Au,
             pub vertical: Au,
         }
 
@@ -55,16 +56,21 @@
             }
 
             #[inline]
             fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
                 Ok(self.horizontal.compute_squared_distance(&other.horizontal)? +
                    self.vertical.compute_squared_distance(&other.vertical)?)
             }
         }
+
+        impl ToAnimatedZero for T {
+            #[inline]
+            fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+        }
     }
 
     #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
     #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
     pub struct SpecifiedValue {
         pub horizontal: Length,
         pub vertical: Option<Length>,
     }
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -5,20 +5,20 @@
 // This file is a Mako template: http://www.makotemplates.org/
 
 // Please note that valid Rust syntax may be mangled by the Mako parser.
 // For example, Vec<&Foo> will be mangled as Vec&Foo>. To work around these issues, the code
 // can be escaped. In the above example, Vec<<&Foo> or Vec< &Foo> achieves the desired result of Vec<&Foo>.
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
+use servo_arc::{Arc, UniqueArc};
 use std::borrow::Cow;
 use std::collections::HashSet;
 use std::{fmt, mem, ops};
-use stylearc::{Arc, UniqueArc};
 
 use app_units::Au;
 #[cfg(feature = "servo")] use cssparser::RGBA;
 use cssparser::{Parser, TokenSerializationType, serialize_identifier};
 use cssparser::ParserInput;
 #[cfg(feature = "servo")] use euclid::SideOffsets2D;
 use computed_values;
 use context::QuirksMode;
@@ -1476,17 +1476,17 @@ impl PropertyDeclaration {
                       "Declarations are only expected inside a keyframe, page, or style rule.");
         id.check_allowed_in(rule_type, context.stylesheet_origin)?;
         match id {
             PropertyId::Custom(name) => {
                 let value = match input.try(|i| CSSWideKeyword::parse(context, i)) {
                     Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword),
                     Err(_) => match ::custom_properties::SpecifiedValue::parse(context, input) {
                         Ok(value) => DeclaredValueOwned::Value(value),
-                        Err(_) => return Err(PropertyDeclarationParseError::InvalidValue(name.to_string())),
+                        Err(_) => return Err(PropertyDeclarationParseError::InvalidValue(name.to_string().into())),
                     }
                 };
                 declarations.push(PropertyDeclaration::Custom(name, value));
                 Ok(())
             }
             PropertyId::Longhand(id) => {
                 input.try(|i| CSSWideKeyword::parse(context, i)).map(|keyword| {
                     PropertyDeclaration::CSSWideKeyword(id, keyword)
@@ -2347,23 +2347,23 @@ pub fn get_writing_mode(inheritedbox_sty
             },
         }
     }
     % endif
     flags
 }
 
 % if product == "gecko":
-    pub use ::stylearc::RawOffsetArc as BuilderArc;
+    pub use ::servo_arc::RawOffsetArc as BuilderArc;
     /// Clone an arc, returning a regular arc
     fn clone_arc<T: 'static>(x: &BuilderArc<T>) -> Arc<T> {
         Arc::from_raw_offset(x.clone())
     }
 % else:
-    pub use ::stylearc::Arc as BuilderArc;
+    pub use ::servo_arc::Arc as BuilderArc;
     /// Clone an arc, returning a regular arc
     fn clone_arc<T: 'static>(x: &BuilderArc<T>) -> Arc<T> {
         x.clone()
     }
 % endif
 
 /// A reference to a style struct of the parent, or our own style struct.
 pub enum StyleStructRef<'a, T: 'static> {
@@ -2648,17 +2648,17 @@ impl<'a> StyleBuilder<'a> {
 #[cfg(feature = "servo")]
 pub use self::lazy_static_module::INITIAL_SERVO_VALUES;
 
 // Use a module to work around #[cfg] on lazy_static! not being applied to every generated item.
 #[cfg(feature = "servo")]
 #[allow(missing_docs)]
 mod lazy_static_module {
     use logical_geometry::WritingMode;
-    use stylearc::Arc;
+    use servo_arc::Arc;
     use super::{ComputedValues, ComputedValuesInner, longhands, style_structs, FontComputationData};
     use super::computed_value_flags::ComputedValueFlags;
 
     /// The initial values for all style structs as defined by the specification.
     lazy_static! {
         pub static ref INITIAL_SERVO_VALUES: ComputedValues = ComputedValues {
             inner: ComputedValuesInner {
                 % for style_struct in data.active_style_structs():
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -5,23 +5,23 @@
 #![allow(unsafe_code)]
 
 //! The rule tree.
 
 use applicable_declarations::ApplicableDeclarationList;
 #[cfg(feature = "servo")]
 use heapsize::HeapSizeOf;
 use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
+use servo_arc::{Arc, ArcBorrow, NonZeroPtrMut};
 use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
 use smallvec::SmallVec;
 use std::io::{self, Write};
 use std::mem;
 use std::ptr;
 use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
-use stylearc::{Arc, ArcBorrow, NonZeroPtrMut};
 use stylesheets::StyleRule;
 use thread_state;
 
 /// The rule tree, the structure servo uses to preserve the results of selector
 /// matching.
 ///
 /// This is organized as a tree of rules. When a node matches a set of rules,
 /// they're inserted in order in the tree, starting with the less specific one.
--- a/servo/components/style/servo/url.rs
+++ b/servo/components/style/servo/url.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Common handling for the specified value CSS url() values.
 
 use parser::ParserContext;
 use servo_url::ServoUrl;
 use std::fmt;
-// Note: We use std::sync::Arc rather than stylearc::Arc here because the
+// Note: We use std::sync::Arc rather than servo_arc::Arc here because the
 // nonzero optimization is important in keeping the size of SpecifiedUrl below
 // the threshold.
 use std::sync::Arc;
 use style_traits::{ToCss, ParseError};
 
 /// A specified url() value for servo.
 ///
 /// Servo eagerly resolves SpecifiedUrls, which it can then take advantage of
--- a/servo/components/style/shared_lock.rs
+++ b/servo/components/style/shared_lock.rs
@@ -3,21 +3,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Different objects protected by the same lock
 
 #[cfg(feature = "gecko")]
 use atomic_refcell::{AtomicRefCell, AtomicRef, AtomicRefMut};
 #[cfg(feature = "servo")]
 use parking_lot::RwLock;
+use servo_arc::Arc;
 use std::cell::UnsafeCell;
 use std::fmt;
 #[cfg(feature = "gecko")]
 use std::ptr;
-use stylearc::Arc;
 
 /// A shared read/write lock that can protect multiple objects.
 ///
 /// In Gecko builds, we don't need the blocking behavior, just the safety. As
 /// such we implement this with an AtomicRefCell instead in Gecko builds,
 /// which is ~2x as fast, and panics (rather than deadlocking) when th