Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 12 Feb 2017 15:28:29 -0800
changeset 342474 00d16f03506b7f9f754b01a0a458c05445ac6dba
parent 342473 43270c88b2513a6758a0ce6669559f4a5f3c9207 (current diff)
parent 342426 80faf8e53b8267235fa512424ef161b5129f00d7 (diff)
child 342475 50dd84db770893c4afbfdc3f68faaac046315c96
child 342490 c9c650a299874a6d629f95d1b71012e18d0f5854
push id86869
push userphilringnalda@gmail.com
push dateSun, 12 Feb 2017 23:33:45 +0000
treeherdermozilla-inbound@50dd84db7708 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone54.0a1
first release with
nightly linux32
00d16f03506b / 54.0a1 / 20170213110223 / files
nightly linux64
00d16f03506b / 54.0a1 / 20170213110223 / files
nightly mac
00d16f03506b / 54.0a1 / 20170213030206 / files
nightly win32
00d16f03506b / 54.0a1 / 20170213030206 / files
nightly win64
00d16f03506b / 54.0a1 / 20170213030206 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-i to m-c, a=merge
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -2136,18 +2136,24 @@ Accessible::RemoveChild(Accessible* aChi
 
   if (aChild->mParent != this || aChild->mIndexInParent == -1)
     return false;
 
   MOZ_ASSERT((mStateFlags & eKidsMutating) || aChild->IsDefunct() || aChild->IsDoc(),
              "Illicit children change");
 
   int32_t index = static_cast<uint32_t>(aChild->mIndexInParent);
-  MOZ_ASSERT(mChildren.SafeElementAt(index) == aChild,
-             "A wrong child index");
+  if (mChildren.SafeElementAt(index) != aChild) {
+    MOZ_ASSERT_UNREACHABLE("A wrong child index");
+    index = mChildren.IndexOf(aChild);
+    if (index == -1) {
+      MOZ_ASSERT_UNREACHABLE("No child was found");
+      return false;
+    }
+  }
 
   aChild->UnbindFromParent();
   mChildren.RemoveElementAt(index);
 
   for (uint32_t idx = index; idx < mChildren.Length(); idx++) {
     mChildren[idx]->mIndexInParent = idx;
   }
 
--- a/accessible/tests/browser/e10s/browser.ini
+++ b/accessible/tests/browser/e10s/browser.ini
@@ -14,17 +14,17 @@ support-files =
   !/accessible/tests/mochitest/moz.png
 
 # Caching tests
 [browser_caching_attributes.js]
 skip-if = e10s && os == 'win' # Bug 1288839
 [browser_caching_description.js]
 skip-if = e10s && os == 'win' && os_version == '5.1'
 [browser_caching_name.js]
-skip-if = e10s && os == 'win' && os_version == '5.1'
+skip-if = e10s && os == 'win' && debug # Bug 1338034, leaks
 [browser_caching_relations.js]
 skip-if = e10s && os == 'win' && os_version == '5.1'
 [browser_caching_states.js]
 skip-if = e10s && os == 'win' && os_version == '5.1'
 [browser_caching_value.js]
 skip-if = e10s && os == 'win' && os_version == '5.1'
 
 # Events tests
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3724,17 +3724,17 @@
 
               let browser = tab.linkedBrowser;
               let {tabParent} = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
               if (state == this.STATE_LOADING) {
                 this.assert(!this.minimized);
                 browser.docShellIsActive = true;
                 if (!tabParent) {
                   this.onLayersReady(browser);
-		}
+                }
               } else if (state == this.STATE_UNLOADING) {
                 browser.docShellIsActive = false;
                 if (!tabParent) {
                   this.onLayersCleared(browser);
                 }
               }
             },
 
@@ -4168,19 +4168,19 @@
 
             shouldActivateDocShell(browser) {
               let tab = this.tabbrowser.getTabForBrowser(browser);
               let state = this.getTabState(tab);
               return state == this.STATE_LOADING || state == this.STATE_LOADED;
             },
 
             activateBrowserForPrintPreview(browser) {
-	      let tab = this.tabbrowser.getTabForBrowser(browser);
-	      this.setTabState(tab, this.STATE_LOADING);
-	    },
+              let tab = this.tabbrowser.getTabForBrowser(browser);
+              this.setTabState(tab, this.STATE_LOADING);
+            },
 
             // Called when the user asks to switch to a given tab.
             requestTab(tab) {
               if (tab === this.requestedTab) {
                 return;
               }
 
               this.logState("requestTab " + this.tinfo(tab));
@@ -4799,18 +4799,18 @@
             }
             case "Browser:WindowCreated": {
               let tab = this.getTabForBrowser(browser);
               if (tab && data.userContextId) {
                 ContextualIdentityService.telemetry(data.userContextId);
                 tab.setUserContextId(data.userContextId);
               }
 
-	      // We don't want to update the container icon and identifier if
-	      // this is not the selected browser.
+              // We don't want to update the container icon and identifier if
+              // this is not the selected browser.
               if (browser == gBrowser.selectedBrowser) {
                 updateUserContextUIIndicator();
               }
 
               break;
             }
             case "Findbar:Keypress": {
               let tab = this.getTabForBrowser(browser);
--- a/devtools/client/commandline/test/browser_cmd_highlight_04.js
+++ b/devtools/client/commandline/test/browser_cmd_highlight_04.js
@@ -2,16 +2,18 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /* eslint key-spacing: 0 */
 
 // Tests the various highlight command parameters and options
 
+requestLongerTimeout(3);
+
 // Creating a test page with many elements to test the --showall option
 var TEST_PAGE = "data:text/html;charset=utf-8,<body><ul>";
 for (let i = 0; i < 101; i++) {
   TEST_PAGE += "<li class='item'>" + i + "</li>";
 }
 TEST_PAGE += "</ul></body>";
 
 function test() {
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -140,16 +140,17 @@ skip-if = os == "mac" # Bug 1245996 : cl
 [browser_rules_editable-field-focus_02.js]
 [browser_rules_eyedropper.js]
 [browser_rules_filtereditor-appears-on-swatch-click.js]
 [browser_rules_filtereditor-commit-on-ENTER.js]
 [browser_rules_filtereditor-revert-on-ESC.js]
 skip-if = (os == "win" && debug) # bug 963492: win.
 [browser_rules_grid-highlighter-on-navigate.js]
 [browser_rules_grid-toggle_01.js]
+[browser_rules_grid-toggle_01b.js]
 [browser_rules_grid-toggle_02.js]
 [browser_rules_grid-toggle_03.js]
 [browser_rules_guessIndentation.js]
 [browser_rules_inherited-properties_01.js]
 [browser_rules_inherited-properties_02.js]
 [browser_rules_inherited-properties_03.js]
 [browser_rules_inherited-properties_04.js]
 [browser_rules_inline-source-map.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser_rules_grid-toggle_01b.js
@@ -0,0 +1,64 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test toggling the grid highlighter in the rule view and the display of the
+// grid highlighter.
+
+const TEST_URI = `
+  <style type='text/css'>
+    #grid {
+      display: inline-grid;
+    }
+  </style>
+  <div id="grid">
+    <div id="cell1">cell1</div>
+    <div id="cell2">cell2</div>
+  </div>
+`;
+
+const HIGHLIGHTER_TYPE = "CssGridHighlighter";
+
+add_task(function* () {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  let {inspector, view} = yield openRuleView();
+  let highlighters = view.highlighters;
+
+  yield selectNode("#grid", inspector);
+  let container = getRuleViewProperty(view, "#grid", "display").valueSpan;
+  let gridToggle = container.querySelector(".ruleview-grid");
+
+  info("Checking the initial state of the CSS grid toggle in the rule-view.");
+  ok(gridToggle, "Grid highlighter toggle is visible.");
+  ok(!gridToggle.classList.contains("active"),
+    "Grid highlighter toggle button is not active.");
+  ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
+    "No CSS grid highlighter exists in the rule-view.");
+  ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+
+  info("Toggling ON the CSS grid highlighter from the rule-view.");
+  let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+  gridToggle.click();
+  yield onHighlighterShown;
+
+  info("Checking the CSS grid highlighter is created and toggle button is active in " +
+    "the rule-view.");
+  ok(gridToggle.classList.contains("active"),
+    "Grid highlighter toggle is active.");
+  ok(highlighters.highlighters[HIGHLIGHTER_TYPE],
+    "CSS grid highlighter created in the rule-view.");
+  ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+
+  info("Toggling OFF the CSS grid highlighter from the rule-view.");
+  let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+  gridToggle.click();
+  yield onHighlighterHidden;
+
+  info("Checking the CSS grid highlighter is not shown and toggle button is not active " +
+    "in the rule-view.");
+  ok(!gridToggle.classList.contains("active"),
+    "Grid highlighter toggle button is not active.");
+  ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+});
--- a/devtools/client/inspector/rules/views/text-property-editor.js
+++ b/devtools/client/inspector/rules/views/text-property-editor.js
@@ -863,18 +863,20 @@ TextPropertyEditor.prototype = {
    *
    * @return {Boolean} true if the property value is valid, false otherwise.
    */
   isValid: function () {
     return this.prop.isValid();
   },
 
   /**
-   * Returns true if the property is a `display: grid` declaration.
+   * Returns true if the property is a `display: [inline-]grid` declaration.
    *
-   * @return {Boolean} true if the property is a `display: grid` declaration.
+   * @return {Boolean} true if the property is a `display: [inline-]grid` declaration.
    */
   isDisplayGrid: function () {
-    return this.prop.name === "display" && this.prop.value === "grid";
+    return this.prop.name === "display" &&
+      (this.prop.value === "grid" ||
+       this.prop.value === "inline-grid");
   }
 };
 
 exports.TextPropertyEditor = TextPropertyEditor;
--- a/devtools/client/shared/output-parser.js
+++ b/devtools/client/shared/output-parser.js
@@ -204,18 +204,17 @@ OutputParser.prototype = {
           break;
         }
 
         case "ident":
           if (options.expectCubicBezier &&
               BEZIER_KEYWORDS.indexOf(token.text) >= 0) {
             this._appendCubicBezier(token.text, options);
           } else if (Services.prefs.getBoolPref(CSS_GRID_ENABLED_PREF) &&
-                     options.expectDisplay && token.text === "grid" &&
-                     text === token.text) {
+                     this._isDisplayGrid(text, token, options)) {
             this._appendGrid(token.text, options);
           } else if (colorOK() &&
                      colorUtils.isValidCSSColor(token.text, this.cssColor4)) {
             this._appendColor(token.text, options);
           } else if (angleOK(token.text)) {
             this._appendAngle(token.text, options);
           } else {
             this._appendTextNode(text.substring(token.startOffset,
@@ -281,16 +280,34 @@ OutputParser.prototype = {
     if (options.expectFilter && !options.filterSwatch) {
       result = this._wrapFilter(text, options, result);
     }
 
     return result;
   },
 
   /**
+   * Return true if it's a display:[inline-]grid token.
+   *
+   * @param  {String} text
+   *         the parsed text.
+   *
+   * @param  {Object} token
+   *         the parsed token.
+   *
+   * @param  {Object} options
+   *         the options given to _parse.
+   */
+  _isDisplayGrid: function (text, token, options) {
+    return options.expectDisplay &&
+      (token.text === "grid" || token.text === "inline-grid") &&
+      text === token.text;
+  },
+
+  /**
    * Append a cubic-bezier timing function value to the output
    *
    * @param {String} bezier
    *        The cubic-bezier timing function
    * @param {Object} options
    *        Options object. For valid options and default values see
    *        _mergeOptions()
    */
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -49,17 +49,17 @@ const GRID_GAP_PATTERN_STROKE_STYLE = "#
 const gCachedGridPattern = new WeakMap();
 // WeakMap key for the Row grid pattern.
 const ROW_KEY = {};
 // WeakMap key for the Column grid pattern.
 const COLUMN_KEY = {};
 
 /**
  * The CssGridHighlighter is the class that overlays a visual grid on top of
- * display:grid elements.
+ * display:[inline-]grid elements.
  *
  * Usage example:
  * let h = new CssGridHighlighter(env);
  * h.show(node, options);
  * h.hide();
  * h.destroy();
  *
  * Available Options:
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -350,18 +350,16 @@ EffectCompositor::UpdateEffectProperties
   if (!effectSet) {
     return;
   }
 
   // Style context change might cause CSS cascade level,
   // e.g removing !important, so we should update the cascading result.
   effectSet->MarkCascadeNeedsUpdate();
 
-  ClearBaseStyles(*aElement, aPseudoType);
-
   for (KeyframeEffectReadOnly* effect : *effectSet) {
     effect->UpdateProperties(aStyleContext);
   }
 }
 
 void
 EffectCompositor::MaybeUpdateAnimationRule(dom::Element* aElement,
                                            CSSPseudoElementType aPseudoType,
@@ -943,89 +941,16 @@ EffectCompositor::SetPerformanceWarning(
     return;
   }
 
   for (KeyframeEffectReadOnly* effect : *effects) {
     effect->SetPerformanceWarning(aProperty, aWarning);
   }
 }
 
-/* static */ StyleAnimationValue
-EffectCompositor::GetBaseStyle(nsCSSPropertyID aProperty,
-                               nsStyleContext* aStyleContext,
-                               dom::Element& aElement,
-                               CSSPseudoElementType aPseudoType)
-{
-  MOZ_ASSERT(aStyleContext, "Need style context to resolve the base value");
-  MOZ_ASSERT(!aStyleContext->StyleSource().IsServoComputedValues(),
-             "Bug 1311257: Servo backend does not support the base value yet");
-
-  StyleAnimationValue result;
-
-  EffectSet* effectSet =
-    EffectSet::GetEffectSet(&aElement, aPseudoType);
-  if (!effectSet) {
-    return result;
-  }
-
-  // Check whether there is a cached style.
-  result = effectSet->GetBaseStyle(aProperty);
-  if (!result.IsNull()) {
-    return result;
-  }
-
-  RefPtr<nsStyleContext> styleContextWithoutAnimation =
-    aStyleContext->PresContext()->StyleSet()->AsGecko()->
-      ResolveStyleByRemovingAnimation(&aElement, aStyleContext,
-                                      eRestyle_AllHintsWithAnimations);
-
-  DebugOnly<bool> success =
-    StyleAnimationValue::ExtractComputedValue(aProperty,
-                                              styleContextWithoutAnimation,
-                                              result);
-  MOZ_ASSERT(success, "Should be able to extract computed animation value");
-  MOZ_ASSERT(!result.IsNull(), "Should have a valid StyleAnimationValue");
-
-  effectSet->PutBaseStyle(aProperty, result);
-
-  return result;
-}
-
-/* static */ StyleAnimationValue
-EffectCompositor::GetBaseStyle(nsCSSPropertyID aProperty,
-                               const nsIFrame* aFrame)
-{
-  MOZ_ASSERT(aFrame->StyleContext(),
-             "The frame should have a valid style context");
-
-  Maybe<NonOwningAnimationTarget> pseudoElement =
-    EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame);
-
-  MOZ_ASSERT(pseudoElement && pseudoElement->mElement,
-             "The frame should have an associated element");
-
-  return EffectCompositor::GetBaseStyle(aProperty,
-                                        aFrame->StyleContext(),
-                                        *pseudoElement->mElement,
-                                        pseudoElement->mPseudoType);
-}
-
-/* static */ void
-EffectCompositor::ClearBaseStyles(dom::Element& aElement,
-                                  CSSPseudoElementType aPseudoType)
-{
-  EffectSet* effectSet =
-    EffectSet::GetEffectSet(&aElement, aPseudoType);
-  if (!effectSet) {
-    return;
-  }
-
-  effectSet->ClearBaseStyles();
-}
-
 // ---------------------------------------------------------
 //
 // Nested class: AnimationStyleRuleProcessor
 //
 // ---------------------------------------------------------
 
 NS_IMPL_ISUPPORTS(EffectCompositor::AnimationStyleRuleProcessor,
                   nsIStyleRuleProcessor)
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -228,35 +228,16 @@ public:
 
   // Associates a performance warning with effects on |aFrame| that animates
   // |aProperty|.
   static void SetPerformanceWarning(
     const nsIFrame* aFrame,
     nsCSSPropertyID aProperty,
     const AnimationPerformanceWarning& aWarning);
 
-  // Returns the base style of (pseudo-)element for |aProperty|.
-  // If there is no cached base style for the property, a new base style value
-  // is resolved with |aStyleContext|. The new resolved base style is cached
-  // until ClearBaseStyles is called.
-  static StyleAnimationValue GetBaseStyle(nsCSSPropertyID aProperty,
-                                          nsStyleContext* aStyleContext,
-                                          dom::Element& aElement,
-                                          CSSPseudoElementType aPseudoType);
-
-  // Returns the base style corresponding to |aFrame|.
-  // This function should be called only after restyle process has done, i.e.
-  // |aFrame| has a resolved style context.
-  static StyleAnimationValue GetBaseStyle(nsCSSPropertyID aProperty,
-                                          const nsIFrame* aFrame);
-
-  // Clear cached base styles of (pseudo-)element.
-  static void ClearBaseStyles(dom::Element& aElement,
-                              CSSPseudoElementType aPseudoType);
-
 private:
   ~EffectCompositor() = default;
 
   // Rebuilds the animation rule corresponding to |aCascadeLevel| on the
   // EffectSet associated with the specified (pseudo-)element.
   static void ComposeAnimationRule(dom::Element* aElement,
                                    CSSPseudoElementType aPseudoType,
                                    CascadeLevel aCascadeLevel,
--- a/dom/animation/EffectSet.h
+++ b/dom/animation/EffectSet.h
@@ -194,36 +194,16 @@ public:
   {
     return mPropertiesWithImportantRules;
   }
   nsCSSPropertyIDSet& PropertiesForAnimationsLevel()
   {
     return mPropertiesForAnimationsLevel;
   }
 
-  // This function is intended to be called by EffectCompositor::GetBaseStyle
-  // and should not be called directly.
-  StyleAnimationValue GetBaseStyle(nsCSSPropertyID aProperty) const
-  {
-    StyleAnimationValue result;
-    DebugOnly<bool> hasProperty = mBaseStyleValues.Get(aProperty, &result);
-    MOZ_ASSERT(hasProperty || result.IsNull());
-    return result;
-  }
-
-  void PutBaseStyle(nsCSSPropertyID aProperty,
-                    const StyleAnimationValue& aValue)
-  {
-    return mBaseStyleValues.Put(aProperty, aValue);
-  }
-  void ClearBaseStyles()
-  {
-    return mBaseStyleValues.Clear();
-  }
-
 private:
   static nsIAtom* GetEffectSetPropertyAtom(CSSPseudoElementType aPseudoType);
 
   OwningEffectSet mEffects;
 
   // These style rules contain the style data for currently animating
   // values.  They only match when styling with animation.  When we
   // style without animation, we need to not use them so that we can
@@ -262,21 +242,16 @@ private:
   // Specifies the compositor-animatable properties that are overridden by
   // !important rules.
   nsCSSPropertyIDSet mPropertiesWithImportantRules;
   // Specifies the properties for which the result will be added to the
   // animations level of the cascade and hence should be skipped when we are
   // composing the animation style for the transitions level of the cascede.
   nsCSSPropertyIDSet mPropertiesForAnimationsLevel;
 
-  // The non-animated values for properties animated by effects in this set that
-  // contain at least one animation value that is composited with the underlying
-  // value (i.e. it uses the additive or accumulate composite mode).
-  nsDataHashtable<nsUint32HashKey, StyleAnimationValue> mBaseStyleValues;
-
 #ifdef DEBUG
   // Track how many iterators are referencing this effect set when we are
   // destroyed, we can assert that nothing is still pointing to us.
   uint64_t mActiveIterators;
 
   bool mCalledPropertyDtor;
 #endif
 };
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -281,16 +281,20 @@ KeyframeEffectReadOnly::UpdateProperties
   MOZ_DIAGNOSTIC_ASSERT(!mIsComposingStyle,
                         "Should not be called while processing ComposeStyle()");
   if (mIsComposingStyle) {
     return;
   }
 
   nsTArray<AnimationProperty> properties = BuildProperties(aStyleContext);
 
+  // We need to update base styles even if any properties are not changed at all
+  // since base styles might have been changed due to parent style changes, etc.
+  EnsureBaseStyles(aStyleContext, properties);
+
   if (mProperties == properties) {
     return;
   }
 
   // Preserve the state of the mIsRunningOnCompositor flag.
   nsCSSPropertyIDSet runningOnCompositorProperties;
 
   for (const AnimationProperty& property : mProperties) {
@@ -346,39 +350,59 @@ KeyframeEffectReadOnly::CompositeValue(
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown compisite operation type");
       break;
   }
   return StyleAnimationValue();
 }
 
 StyleAnimationValue
+KeyframeEffectReadOnly::ResolveBaseStyle(nsCSSPropertyID aProperty,
+                                         nsStyleContext* aStyleContext)
+{
+  StyleAnimationValue result;
+  if (mBaseStyleValues.Get(aProperty, &result)) {
+    return result;
+  }
+
+  RefPtr<nsStyleContext> styleContextWithoutAnimation =
+    aStyleContext->PresContext()->StyleSet()->AsGecko()->
+      ResolveStyleByRemovingAnimation(mTarget->mElement,
+                                      aStyleContext,
+                                      eRestyle_AllHintsWithAnimations);
+  DebugOnly<bool> success =
+    StyleAnimationValue::ExtractComputedValue(aProperty,
+                                              styleContextWithoutAnimation,
+                                              result);
+
+  MOZ_ASSERT(success, "Should be able to extract computed animation value");
+  MOZ_ASSERT(!result.IsNull(), "Should have a valid StyleAnimationValue");
+
+  mBaseStyleValues.Put(aProperty, result);
+
+  return result;
+}
+
+StyleAnimationValue
 KeyframeEffectReadOnly::GetUnderlyingStyle(
   nsCSSPropertyID aProperty,
   const RefPtr<AnimValuesStyleRule>& aAnimationRule)
 {
   StyleAnimationValue result;
 
   if (aAnimationRule->HasValue(aProperty)) {
     // If we have already composed style for the property, we use the style
     // as the underlying style.
     DebugOnly<bool> success = aAnimationRule->GetValue(aProperty, result);
     MOZ_ASSERT(success, "AnimValuesStyleRule::GetValue should not fail");
   } else {
     // If we are composing with composite operation that is not 'replace'
     // and we have not composed style for the property yet, we have to get
     // the base style for the property.
-    RefPtr<nsStyleContext> styleContext =
-      GetTargetStyleContextWithoutAnimation();
-    result = EffectCompositor::GetBaseStyle(aProperty,
-                                            styleContext,
-                                            *mTarget->mElement,
-                                            mTarget->mPseudoType);
-    MOZ_ASSERT(!result.IsNull(), "The base style should be set");
-    SetNeedsBaseStyle(aProperty);
+    result = BaseStyle(aProperty);
   }
 
   return result;
 }
 
 StyleAnimationValue
 KeyframeEffectReadOnly::CompositeValue(
   nsCSSPropertyID aProperty,
@@ -410,59 +434,34 @@ KeyframeEffectReadOnly::CompositeValue(
 
   return CompositeValue(aProperty,
                         aValueToComposite,
                         result,
                         aCompositeOperation);
 }
 
 void
-KeyframeEffectReadOnly::EnsureBaseStylesForCompositor(
-  const nsCSSPropertyIDSet& aPropertiesToSkip)
+KeyframeEffectReadOnly::EnsureBaseStyles(
+  nsStyleContext* aStyleContext,
+  const nsTArray<AnimationProperty>& aProperties)
 {
   if (!mTarget) {
     return;
   }
 
-  RefPtr<nsStyleContext> styleContext;
-
-  for (const AnimationProperty& property : mProperties) {
-    if (!nsCSSProps::PropHasFlags(property.mProperty,
-                                  CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) {
-      continue;
-    }
+  mBaseStyleValues.Clear();
 
-    if (aPropertiesToSkip.HasProperty(property.mProperty)) {
-      continue;
-    }
-
-    // We only call SetNeedsBaseStyle after calling GetBaseStyle so if
-    // NeedsBaseStyle is true, the base style should be already filled-in.
-    if (NeedsBaseStyle(property.mProperty)) {
-      continue;
-    }
-
+  for (const AnimationProperty& property : aProperties) {
     for (const AnimationPropertySegment& segment : property.mSegments) {
       if (segment.mFromComposite == dom::CompositeOperation::Replace &&
           segment.mToComposite == dom::CompositeOperation::Replace) {
         continue;
       }
 
-      if (!styleContext) {
-        styleContext = GetTargetStyleContextWithoutAnimation();
-      }
-      MOZ_RELEASE_ASSERT(styleContext);
-
-      Unused << EffectCompositor::GetBaseStyle(property.mProperty,
-                                               styleContext,
-                                               *mTarget->mElement,
-                                               mTarget->mPseudoType);
-      // Make this property as needing a base style so that we send the (now
-      // cached) base style to the compositor.
-      SetNeedsBaseStyle(property.mProperty);
+      Unused << ResolveBaseStyle(property.mProperty, aStyleContext);
       break;
     }
   }
 }
 
 void
 KeyframeEffectReadOnly::ComposeStyle(
   AnimationRule& aStyleRule,
@@ -479,34 +478,22 @@ KeyframeEffectReadOnly::ComposeStyle(
 
   ComputedTiming computedTiming = GetComputedTiming();
   mProgressOnLastCompose = computedTiming.mProgress;
   mCurrentIterationOnLastCompose = computedTiming.mCurrentIteration;
 
   // If the progress is null, we don't have fill data for the current
   // time so we shouldn't animate.
   if (computedTiming.mProgress.IsNull()) {
-    // If we are not in-effect, this effect might still be sent to the
-    // compositor and later become in-effect (e.g. if it is in the delay phase,
-    // or, if it is in the end delay phase but with a negative playback rate).
-    // In that case, we might need the base style in order to perform
-    // additive/accumulative animation on the compositor.
-
-    // Note, however, that we don't actually send animations with a negative
-    // playback rate in their end delay phase to the compositor at this stage
-    // (bug 1330498).
-    EnsureBaseStylesForCompositor(aPropertiesToSkip);
     return;
   }
 
   nsPresContext* presContext = GetPresContext();
   bool isServoBackend = presContext && presContext->StyleSet()->IsServo();
 
-  mNeedsBaseStyleSet.Empty();
-
   for (size_t propIdx = 0, propEnd = mProperties.Length();
        propIdx != propEnd; ++propIdx)
   {
     const AnimationProperty& prop = mProperties[propIdx];
 
     MOZ_ASSERT(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key");
     MOZ_ASSERT(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0,
                "incorrect last to key");
@@ -600,16 +587,19 @@ KeyframeEffectReadOnly::ComposeStyle(
       StyleAnimationValue fromValue =
         CompositeValue(prop.mProperty, aStyleRule.mGecko,
                        segment->mFromValue.mGecko,
                        segment->mFromComposite);
       StyleAnimationValue toValue =
         CompositeValue(prop.mProperty, aStyleRule.mGecko,
                        segment->mToValue.mGecko,
                        segment->mToComposite);
+      if (fromValue.IsNull() || toValue.IsNull()) {
+        continue;
+      }
 
       // Iteration composition for accumulate
       if (mEffectOptions.mIterationComposite ==
           IterationCompositeOperation::Accumulate &&
           computedTiming.mCurrentIteration > 0) {
         const AnimationPropertySegment& lastSegment =
           prop.mSegments.LastElement();
         // FIXME: Bug 1293492: Add a utility function to calculate both of
@@ -657,24 +647,16 @@ KeyframeEffectReadOnly::ComposeStyle(
         aStyleRule.mGecko->AddValue(prop.mProperty, Move(val));
       } else if (valuePosition < 0.5) {
         aStyleRule.mGecko->AddValue(prop.mProperty, Move(fromValue));
       } else {
         aStyleRule.mGecko->AddValue(prop.mProperty, Move(toValue));
       }
     }
   }
-
-  // For properties that can be run on the compositor, we may need to prepare
-  // base styles to send to the compositor even if the current processing
-  // segment for properties does not have either an additive or accumulative
-  // composite mode, and even if the animation is not in-effect. That's because
-  // the animation may later progress to a segment which has an additive or
-  // accumulative composite on the compositor mode.
-  EnsureBaseStylesForCompositor(aPropertiesToSkip);
 }
 
 bool
 KeyframeEffectReadOnly::IsRunningOnCompositor() const
 {
   // We consider animation is running on compositor if there is at least
   // one property running on compositor.
   // Animation.IsRunningOnCompotitor will return more fine grained
@@ -963,52 +945,34 @@ KeyframeEffectReadOnly::RequestRestyle(
   nsPresContext* presContext = GetPresContext();
   if (presContext && mTarget && mAnimation) {
     presContext->EffectCompositor()->
       RequestRestyle(mTarget->mElement, mTarget->mPseudoType,
                      aRestyleType, mAnimation->CascadeLevel());
   }
 }
 
-template<KeyframeEffectReadOnly::AnimationStyle aAnimationStyle>
 already_AddRefed<nsStyleContext>
-KeyframeEffectReadOnly::DoGetTargetStyleContext()
+KeyframeEffectReadOnly::GetTargetStyleContext()
 {
   nsIPresShell* shell = GetPresShell();
   if (!shell) {
     return nullptr;
   }
 
   MOZ_ASSERT(mTarget,
              "Should only have a presshell when we have a target element");
 
   nsIAtom* pseudo = mTarget->mPseudoType < CSSPseudoElementType::Count
                     ? nsCSSPseudoElements::GetPseudoAtom(mTarget->mPseudoType)
                     : nullptr;
 
-  if (aAnimationStyle == AnimationStyle::Include) {
-    return nsComputedDOMStyle::GetStyleContextForElement(mTarget->mElement,
-                                                         pseudo,
-                                                         shell);
-  }
-
-  return nsComputedDOMStyle::GetStyleContextForElementWithoutAnimation(
-    mTarget->mElement, pseudo, shell);
-}
-
-already_AddRefed<nsStyleContext>
-KeyframeEffectReadOnly::GetTargetStyleContext()
-{
-  return DoGetTargetStyleContext<AnimationStyle::Include>();
-}
-
-already_AddRefed<nsStyleContext>
-KeyframeEffectReadOnly::GetTargetStyleContextWithoutAnimation()
-{
-  return DoGetTargetStyleContext<AnimationStyle::Skip>();
+  return nsComputedDOMStyle::GetStyleContextForElement(mTarget->mElement,
+                                                       pseudo,
+                                                       shell);
 }
 
 #ifdef DEBUG
 void
 DumpAnimationProperties(nsTArray<AnimationProperty>& aAnimationProperties)
 {
   for (auto& p : aAnimationProperties) {
     printf("%s\n", nsCSSProps::GetStringValue(p.mProperty).get());
@@ -1727,66 +1691,37 @@ KeyframeEffectReadOnly::HasComputedTimin
   ComputedTiming computedTiming = GetComputedTiming();
   return computedTiming.mProgress != mProgressOnLastCompose ||
          (mEffectOptions.mIterationComposite ==
             IterationCompositeOperation::Accumulate &&
          computedTiming.mCurrentIteration !=
           mCurrentIterationOnLastCompose);
 }
 
-void
-KeyframeEffectReadOnly::SetNeedsBaseStyle(nsCSSPropertyID aProperty)
-{
-  for (size_t i = 0; i < LayerAnimationInfo::kRecords; i++) {
-    if (LayerAnimationInfo::sRecords[i].mProperty == aProperty) {
-      mNeedsBaseStyleSet.AddProperty(aProperty);
-      break;
-    }
-  }
-}
-
-bool
-KeyframeEffectReadOnly::NeedsBaseStyle(nsCSSPropertyID aProperty) const
-{
-  for (size_t i = 0; i < LayerAnimationInfo::kRecords; i++) {
-    if (LayerAnimationInfo::sRecords[i].mProperty == aProperty) {
-      return mNeedsBaseStyleSet.HasProperty(aProperty);
-    }
-  }
-  MOZ_ASSERT_UNREACHABLE(
-    "Expected a property that can be run on the compositor");
-
-  return false;
-}
-
 bool
 KeyframeEffectReadOnly::ContainsAnimatedScale(const nsIFrame* aFrame) const
 {
   if (!IsCurrent()) {
     return false;
   }
 
   for (const AnimationProperty& prop : mProperties) {
     if (prop.mProperty != eCSSProperty_transform) {
       continue;
     }
 
-    if (NeedsBaseStyle(prop.mProperty)) {
-      StyleAnimationValue baseStyle =
-        EffectCompositor::GetBaseStyle(prop.mProperty, aFrame);
-      MOZ_ASSERT(!baseStyle.IsNull(), "The base value should be set");
-      if (baseStyle.IsNull()) {
-        // If we failed to get the base style, we consider it has scale value
-        // here for the safety.
-        return true;
-      }
-      gfxSize size = baseStyle.GetScaleValue(aFrame);
-      if (size != gfxSize(1.0f, 1.0f)) {
-        return true;
-      }
+    StyleAnimationValue baseStyle = BaseStyle(prop.mProperty);
+    if (baseStyle.IsNull()) {
+      // If we failed to get the base style, we consider it has scale value
+      // here just to be safe.
+      return true;
+    }
+    gfxSize size = baseStyle.GetScaleValue(aFrame);
+    if (size != gfxSize(1.0f, 1.0f)) {
+      return true;
     }
 
     // This is actually overestimate because there are some cases that combining
     // the base value and from/to value produces 1:1 scale. But it doesn't
     // really matter.
     for (const AnimationPropertySegment& segment : prop.mSegments) {
       if (!segment.mFromValue.IsNull()) {
         gfxSize from = segment.mFromValue.GetScaleValue(aFrame);
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -279,24 +279,28 @@ public:
   void CalculateCumulativeChangeHint(nsStyleContext* aStyleContext);
 
   // Returns true if all of animation properties' change hints
   // can ignore painting if the animation is not visible.
   // See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
   // in detail which change hint can be ignored.
   bool CanIgnoreIfNotVisible() const;
 
-  // Returns true if the effect is run on the compositor for |aProperty| and
-  // needs a base style to composite with.
-  bool NeedsBaseStyle(nsCSSPropertyID aProperty) const;
-
   // Returns true if the effect is current state and has scale animation.
   // |aFrame| is used for calculation of scale values.
   bool ContainsAnimatedScale(const nsIFrame* aFrame) const;
 
+  StyleAnimationValue BaseStyle(nsCSSPropertyID aProperty) const
+  {
+    StyleAnimationValue result;
+    DebugOnly<bool> hasProperty = mBaseStyleValues.Get(aProperty, &result);
+    MOZ_ASSERT(hasProperty || result.IsNull());
+    return result;
+  }
+
 protected:
   KeyframeEffectReadOnly(nsIDocument* aDocument,
                          const Maybe<OwningAnimationTarget>& aTarget,
                          AnimationEffectTimingReadOnly* aTiming,
                          const KeyframeEffectParams& aOptions);
 
   ~KeyframeEffectReadOnly() override = default;
 
@@ -346,28 +350,16 @@ protected:
 
   // Looks up the style context associated with the target element, if any.
   // We need to be careful to *not* call this when we are updating the style
   // context. That's because calling GetStyleContextForElement when we are in
   // the process of building a style context may trigger various forms of
   // infinite recursion.
   already_AddRefed<nsStyleContext> GetTargetStyleContext();
 
-  // Similar to the above but ignoring animation rules. We use this to get base
-  // styles (which don't include animation rules).
-  already_AddRefed<nsStyleContext>
-  GetTargetStyleContextWithoutAnimation();
-
-  enum AnimationStyle {
-    Skip,
-    Include
-  };
-  template<AnimationStyle aAnimationStyle>
-  already_AddRefed<nsStyleContext> DoGetTargetStyleContext();
-
   // A wrapper for marking cascade update according to the current
   // target and its effectSet.
   void MarkCascadeNeedsUpdate();
 
   // Composites |aValueToComposite| using |aCompositeOperation| onto the value
   // for |aProperty| in |aAnimationRule|, or, if there is no suitable value in
   // |aAnimationRule|, uses the base value for the property recorded on the
   // target element's EffectSet.
@@ -377,24 +369,23 @@ protected:
     const StyleAnimationValue& aValueToComposite,
     CompositeOperation aCompositeOperation);
 
   // Returns underlying style animation value for |aProperty|.
   StyleAnimationValue GetUnderlyingStyle(
     nsCSSPropertyID aProperty,
     const RefPtr<AnimValuesStyleRule>& aAnimationRule);
 
-  // Set a bit in mNeedsBaseStyleSet if |aProperty| can be run on the
-  // compositor.
-  void SetNeedsBaseStyle(nsCSSPropertyID aProperty);
+  // Ensure the base styles is available for any properties in |aProperties|.
+  void EnsureBaseStyles(nsStyleContext* aStyleContext,
+                        const nsTArray<AnimationProperty>& aProperties);
 
-  // Ensure the base styles is available for any properties that can be run on
-  // the compositor and which are not includes in |aPropertiesToSkip|.
-  void EnsureBaseStylesForCompositor(
-    const nsCSSPropertyIDSet& aPropertiesToSkip);
+  // Returns the base style resolved by |aStyleContext| for |aProperty|.
+  StyleAnimationValue ResolveBaseStyle(nsCSSPropertyID aProperty,
+                                       nsStyleContext* aStyleContext);
 
   Maybe<OwningAnimationTarget> mTarget;
 
   KeyframeEffectParams mEffectOptions;
 
   // The specified keyframes.
   nsTArray<Keyframe>          mKeyframes;
 
@@ -410,20 +401,20 @@ protected:
   // this is used to detect when the current iteration is not changing
   // in the case when iterationComposite is accumulate.
   uint64_t mCurrentIterationOnLastCompose = 0;
 
   // We need to track when we go to or from being "in effect" since
   // we need to re-evaluate the cascade of animations when that changes.
   bool mInEffectOnLastAnimationTimingUpdate;
 
-  // Represents whether or not the corresponding property requires a base style
-  // to composite with. This is only set when the property is run on the
-  // compositor.
-  nsCSSPropertyIDSet mNeedsBaseStyleSet;
+  // The non-animated values for properties in this effect that contain at
+  // least one animation value that is composited with the underlying value
+  // (i.e. it uses the additive or accumulate composite mode).
+  nsDataHashtable<nsUint32HashKey, StyleAnimationValue> mBaseStyleValues;
 
 private:
   nsChangeHint mCumulativeChangeHint;
 
   nsIFrame* GetAnimationFrame() const;
 
   bool CanThrottle() const;
   bool CanThrottleTransformChanges(nsIFrame& aFrame) const;
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -575,16 +575,21 @@ AsyncCompositionManager::AlignFixedAndSt
 }
 
 static void
 ApplyAnimatedValue(Layer* aLayer,
                    nsCSSPropertyID aProperty,
                    const AnimationData& aAnimationData,
                    const StyleAnimationValue& aValue)
 {
+  if (aValue.IsNull()) {
+    // Return gracefully if we have no valid StyleAnimationValue.
+    return;
+  }
+
   HostLayer* layerCompositor = aLayer->AsHostLayer();
   switch (aProperty) {
     case eCSSProperty_opacity: {
       MOZ_ASSERT(aValue.GetUnit() == StyleAnimationValue::eUnit_Float,
                  "Interpolated value for opacity should be float");
       layerCompositor->SetShadowOpacity(aValue.GetFloatValue());
       layerCompositor->SetShadowOpacitySetByAnimation(true);
       break;
new file mode 100644
--- /dev/null
+++ b/gfx/tests/crashtests/1331683.html
@@ -0,0 +1,2 @@
+<!-- crashtest for bug 1331683 on Mac OS X 10.9/10.10 -->
+<div style="font-family:Skia">hello world</div>
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -128,8 +128,9 @@ load 1034403-1.html
 load 1205900.html
 load 1134549-1.svg
 load balinese-letter-spacing.html
 load 1216832-1.html
 load 1225125-1.html
 load 1308394.html
 skip-if(stylo) load 1317403-1.html # bug 1331533
 load 1325159-1.html
+load 1331683.html
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1288946-1.html
@@ -0,0 +1,9 @@
+<head id=test0>>
+<body id=test2>}Uh<map name=foo id=test3 alt="" href=http://a\b:c\d@foo.com</body><style>
+* { kwidth: 104; letter-spacing: 25710.0134799cm;</style><script>
+test2.style.display = "initial"
+try{test3.insertBefore(test0, test3.childNodes[0 % test3.childNodes.length]); } catch(e) { try{;}catch(e){} }
+test0.parentNode.style.display = "contents"
+window.scrollTo();
+test0.outerHTML = "	~M2Wnj	S`awf##	Ok	57=		x?	7,	,nFQU=L		RvKD	K5	6	s	qb.0cG	i~av_:	bY5Hr		D%~u6:;";
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1288946-2a.html
@@ -0,0 +1,13 @@
+<body style="width:0"><strong>a b<span id="span"><script>
+var code = document.createElement("code");
+var small = document.createElement("small");
+small.appendChild(document.createTextNode("x"));
+
+document.implementation;
+
+span.insertBefore(code, span.firstChild);
+span.style.display = "contents";
+window.scrollTo();
+code.remove();
+span.insertBefore(small, span.firstChild);
+</script></strong>
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1288946-2b.html
@@ -0,0 +1,13 @@
+<body style="width:0"><strong>a b<span id="span"><script>
+var code = document.createElement("code");
+var small = document.createElement("span");
+small.appendChild(document.createTextNode("x"));
+
+document.implementation;
+
+span.insertBefore(code, span.firstChild);
+span.style.display = "contents";
+window.scrollTo();
+code.remove();
+span.insertBefore(small, span.firstChild);
+</script></strong>
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -471,14 +471,17 @@ pref(layout.css.grid.enabled,true) load 
 load 1162813.xul
 load 1163583.html
 load 1234622-1.html
 load 1235467-1.html
 skip-if(stylo) pref(dom.webcomponents.enabled,true) load 1261351.html # bug 1323689
 load 1270797-1.html
 load 1278455-1.html
 load 1286889.html
+load 1288608.html
+load 1288946-1.html
+load 1288946-2a.html
+load 1288946-2b.html
 load 1297835.html
-load 1288608.html
 load 1299736-1.html
 load 1308793.svg
 load 1308848-1.html
 load 1308848-2.html
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -582,20 +582,18 @@ GetMinAndMaxScaleForAnimationProperty(co
     for (size_t propIdx = effect->Properties().Length(); propIdx-- != 0; ) {
       const AnimationProperty& prop = effect->Properties()[propIdx];
       if (prop.mProperty != eCSSProperty_transform) {
         continue;
       }
 
       // We need to factor in the scale of the base style if the base style
       // will be used on the compositor.
-      if (effect->NeedsBaseStyle(prop.mProperty)) {
-        StyleAnimationValue baseStyle =
-          EffectCompositor::GetBaseStyle(prop.mProperty, aFrame);
-        MOZ_ASSERT(!baseStyle.IsNull(), "The base value should be set");
+      StyleAnimationValue baseStyle = effect->BaseStyle(prop.mProperty);
+      if (!baseStyle.IsNull()) {
         // FIXME: Bug 1311257: We need to get the baseStyle for
         //        RawServoAnimationValue.
         UpdateMinMaxScale(aFrame, { baseStyle, nullptr }, aMinScale, aMaxScale);
       }
 
       for (const AnimationPropertySegment& segment : prop.mSegments) {
         // In case of add or accumulate composite, StyleAnimationValue does
         // not have a valid value.
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -488,16 +488,44 @@ private:
       , mRecentVsync(TimeStamp::Now())
       , mLastChildTick(TimeStamp::Now())
       , mVsyncRate(TimeDuration::Forever())
       , mProcessedVsync(true)
     {
       MOZ_ASSERT(NS_IsMainThread());
     }
 
+    class ParentProcessVsyncNotifier final: public Runnable,
+                                            public nsIRunnablePriority
+    {
+    public:
+      ParentProcessVsyncNotifier(RefreshDriverVsyncObserver* aObserver,
+                                 TimeStamp aVsyncTimestamp)
+        : mObserver(aObserver), mVsyncTimestamp(aVsyncTimestamp) {}
+
+      NS_DECL_ISUPPORTS_INHERITED
+
+      NS_IMETHOD Run() override
+      {
+        mObserver->TickRefreshDriver(mVsyncTimestamp);
+        return NS_OK;
+      }
+
+      NS_IMETHOD GetPriority(uint32_t* aPriority) override
+      {
+        *aPriority = nsIRunnablePriority::PRIORITY_HIGH;
+        return NS_OK;
+      }
+
+    private:
+      ~ParentProcessVsyncNotifier() {}
+      RefPtr<RefreshDriverVsyncObserver> mObserver;
+      TimeStamp mVsyncTimestamp;
+    };
+
     bool NotifyVsync(TimeStamp aVsyncTimestamp) override
     {
       if (!NS_IsMainThread()) {
         MOZ_ASSERT(XRE_IsParentProcess());
         // Compress vsync notifications such that only 1 may run at a time
         // This is so that we don't flood the refresh driver with vsync messages
         // if the main thread is blocked for long periods of time
         { // scope lock
@@ -505,19 +533,17 @@ private:
           mRecentVsync = aVsyncTimestamp;
           if (!mProcessedVsync) {
             return true;
           }
           mProcessedVsync = false;
         }
 
         nsCOMPtr<nsIRunnable> vsyncEvent =
-             NewRunnableMethod<TimeStamp>(this,
-                                          &RefreshDriverVsyncObserver::TickRefreshDriver,
-                                          aVsyncTimestamp);
+          new ParentProcessVsyncNotifier(this, aVsyncTimestamp);
         NS_DispatchToMainThread(vsyncEvent);
       } else {
         TickRefreshDriver(aVsyncTimestamp);
       }
 
       return true;
     }
 
@@ -701,16 +727,21 @@ private:
   RefPtr<RefreshTimerVsyncDispatcher> mVsyncDispatcher;
   // Used for child process.
   // The mVsyncChild will be always available before VsncChild::ActorDestroy().
   // After ActorDestroy(), StartTimer() and StopTimer() calls will be non-op.
   RefPtr<VsyncChild> mVsyncChild;
   TimeDuration mVsyncRate;
 }; // VsyncRefreshDriverTimer
 
+NS_IMPL_ISUPPORTS_INHERITED(VsyncRefreshDriverTimer::
+                            RefreshDriverVsyncObserver::
+                            ParentProcessVsyncNotifier,
+                            Runnable, nsIRunnablePriority)
+
 /**
  * Since the content process takes some time to setup
  * the vsync IPC connection, this timer is used
  * during the intial startup process.
  * During initial startup, the refresh drivers
  * are ticked off this timer, and are swapped out once content
  * vsync IPC connection is established.
  */
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/1278080.html
@@ -0,0 +1,31 @@
+<style>
+.columns {
+  -moz-columns: 5;
+       columns: 5;
+  -moz-column-fill: auto;
+       column-fill: auto;
+  height: 100px;
+}
+.grid {
+  display: grid;
+  max-height: 180px;
+  grid-auto-rows: 30px;
+  grid-gap: 12px;
+}
+span {
+  grid-row: 2;
+}
+i { 
+  display: block; 
+  height: 60px; 
+}
+</style>
+<div class="columns"><div class="grid"><span><i></i></span></div></div>
+<script>
+window.onload = function(){
+  var x = document.createElementNS("http://www.w3.org/1999/xhtml", "x");
+  var r = new Range();
+  r.selectNode(document.getElementsByTagName('span')[0]);
+  setTimeout(function(){ r.surroundContents(x); }, 1);
+};
+</script>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -630,16 +630,17 @@ asserts-if(stylo,5) load text-overflow-f
 asserts-if(stylo,1) load text-overflow-iframe.html # bug 1324671
 asserts-if(Android,2-4) asserts-if(!Android,4) asserts-if(stylo,0) load 1225005.html # bug 682647 and bug 448083
 load 1233191.html
 asserts-if(stylo,1-16) load 1271765.html # bug 1324684
 asserts(2) load 1272983-1.html # bug 1324654 # bug 586628
 asserts(2) load 1272983-2.html # bug 1324654 # bug 586628
 load 1275059.html
 load 1278007.html
+load 1278080.html
 load 1279814.html
 load large-border-radius-dashed.html
 load large-border-radius-dashed2.html
 load large-border-radius-dotted.html
 load large-border-radius-dotted2.html
 load 1278461-1.html
 load 1278461-2.html
 asserts-if(stylo,6) load 1281102.html # bug 1324661
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -464,34 +464,16 @@ SetAnimatable(nsCSSPropertyID aProperty,
       break;
     }
     default:
       MOZ_ASSERT_UNREACHABLE("Unsupported property");
   }
 }
 
 static void
-SetBaseAnimationStyle(nsCSSPropertyID aProperty,
-                      nsIFrame* aFrame,
-                      TransformReferenceBox& aRefBox,
-                      layers::Animatable& aBaseStyle)
-{
-  MOZ_ASSERT(aFrame);
-
-  StyleAnimationValue baseValue =
-    EffectCompositor::GetBaseStyle(aProperty, aFrame);
-  MOZ_ASSERT(!baseValue.IsNull(),
-             "The base value should be already there");
-
-  // FIXME: Bug 1311257: We need to get the baseValue for
-  //        RawServoAnimationValue.
-  SetAnimatable(aProperty, { baseValue, nullptr }, aFrame, aRefBox, aBaseStyle);
-}
-
-static void
 AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
                         dom::Animation* aAnimation, Layer* aLayer,
                         AnimationData& aData, bool aPending)
 {
   MOZ_ASSERT(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
   MOZ_ASSERT(aAnimation->GetEffect(),
              "Should not be adding an animation without an effect");
   MOZ_ASSERT(!aAnimation->GetCurrentOrPendingStartTime().IsNull() ||
@@ -556,21 +538,26 @@ AddAnimationForProperty(nsIFrame* aFrame
     static_cast<uint8_t>(aAnimation->GetEffect()->
                          AsKeyframeEffect()->IterationComposite());
   animation->isNotPlaying() = !aAnimation->IsPlaying();
 
   TransformReferenceBox refBox(aFrame);
 
   // If the animation is additive or accumulates, we need to pass its base value
   // to the compositor.
-  if (aAnimation->GetEffect()->AsKeyframeEffect()->
-        NeedsBaseStyle(aProperty.mProperty)) {
-    SetBaseAnimationStyle(aProperty.mProperty,
-                          aFrame, refBox,
-                          animation->baseStyle());
+
+  StyleAnimationValue baseStyle =
+    aAnimation->GetEffect()->AsKeyframeEffect()->BaseStyle(aProperty.mProperty);
+  if (!baseStyle.IsNull()) {
+    // FIXME: Bug 1311257: We need to get the baseValue for
+    //        RawServoAnimationValue.
+    SetAnimatable(aProperty.mProperty,
+                  { baseStyle, nullptr },
+                  aFrame, refBox,
+                  animation->baseStyle());
   } else {
     animation->baseStyle() = null_t();
   }
 
   for (uint32_t segIdx = 0; segIdx < aProperty.mSegments.Length(); segIdx++) {
     const AnimationPropertySegment& segment = aProperty.mSegments[segIdx];
 
     AnimationSegment* animSegment = animation->segments().AppendElement();
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -594,17 +594,17 @@ fails-if(Android&&!asyncPan) != 367247-l
 == 367504-float-1.html 367504-float-1-ref.html
 == 367612-1a.html 367612-1-ref.html
 == 367612-1b.html 367612-1-ref.html
 == 367612-1c.html 367612-1-ref.html
 == 367612-1d.html 367612-1-ref.html
 == 367612-1e.html 367612-1-ref.html
 == 367612-1f.html 367612-1-ref.html
 != 367612-1g.html 367612-1-ref.html
-fuzzy-if(winWidget,5,2) fuzzy-if(skiaContent,1,28) == 368020-1.html 368020-1-ref.html
+fuzzy-if(winWidget||gtkWidget,32,34) fuzzy-if(skiaContent,1,28) == 368020-1.html 368020-1-ref.html
 == 368020-2.html 368020-2-ref.html
 == 368020-3.html 368020-3-ref.html
 pref(layout.css.box-decoration-break.enabled,true) == 368020-5.html 368020-5-ref.html
 == 368155-1.xhtml 368155-1-ref.xhtml
 asserts(4) == 368155-negative-margins-1.html 368155-negative-margins-1-ref.html # bug 387205 / bug 457397
 # we can't test this because there's antialiasing involved, and our comparison
 # is too exact
 # == 368247-1.html 368247-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/checkbox/checkbox-radio-color-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference for bug 1338293</title>
+  <style type="text/css">
+
+.none {
+  display:inline-block;
+  width:0; height:0; margin:0;
+}
+
+.b { border: 20px solid; }
+.o { outline: 20px solid; }
+
+  </style>
+</head>
+<body>
+
+<span class="none b" type="checkbox"></span>
+<span class="none o" type="checkbox"></span>
+
+<span class="none b" type="radio"></span>
+<span class="none o" type="radio"></span>
+
+<div style="color:green">
+<span class="none b" type="checkbox"></span>
+<span class="none o" type="checkbox"></span>
+
+<span class="none b" type="radio"></span>
+<span class="none o" type="radio"></span>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/checkbox/checkbox-radio-color.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Testcase for bug 1338293</title>
+  <style type="text/css">
+
+.none {
+     -moz-appearance: none;
+  -webkit-appearance: none;
+          appearance: none;
+  width:0; height:0; margin:0;
+}
+
+.b { border: 20px solid; }
+.o { outline: 20px solid; }
+
+  </style>
+</head>
+<body>
+
+<input class="none b" type="checkbox">
+<input class="none o" type="checkbox">
+
+<input class="none b" type="radio">
+<input class="none o" type="radio">
+
+<div style="color:green">
+<input class="none b" type="checkbox">
+<input class="none o" type="checkbox">
+
+<input class="none b" type="radio">
+<input class="none o" type="radio">
+</div>
+
+</body>
+</html>
--- a/layout/reftests/forms/input/checkbox/reftest.list
+++ b/layout/reftests/forms/input/checkbox/reftest.list
@@ -7,9 +7,10 @@ fails-if(Android) == unchecked-appearanc
 != checked-native-notref.html about:blank
 fails-if(Android) == indeterminate-checked.html about:blank
 fails-if(Android) == indeterminate-checked-notref.html about:blank
 fails-if(Android) == indeterminate-unchecked.html about:blank
 != indeterminate-native-checked.html indeterminate-native-checked-notref.html
 != indeterminate-native-unchecked.html indeterminate-native-unchecked-notref.html
 == indeterminate-selector.html indeterminate-selector-ref.html
 skip-if(!gtkWidget) == gtk-theme-width-height.html gtk-theme-width-height-ref.html
-skip-if(Android) == checkbox-baseline.html checkbox-baseline-ref.html # skip-if(Android) because Android use appearance:none by default for checkbox/radio.
\ No newline at end of file
+skip-if(Android) == checkbox-baseline.html checkbox-baseline-ref.html # skip-if(Android) because Android use appearance:none by default for checkbox/radio.
+skip-if(Android) == checkbox-radio-color.html checkbox-radio-color-ref.html # skip-if(Android) because Android use appearance:none by default for checkbox/radio.
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -570,16 +570,17 @@ input[type="radio"],
 input[type="checkbox"] {
   box-sizing: border-box;
   cursor: default;
   /* unset some values from the general 'input' rule above: */
   padding: unset;
   -moz-binding: unset;
   border: unset;
   background-color: unset;
+  color: unset;
 }
 
 input[type="radio"]:disabled,
 input[type="radio"]:disabled:active,
 input[type="radio"]:disabled:hover,
 input[type="radio"]:disabled:hover:active,
 input[type="checkbox"]:disabled,
 input[type="checkbox"]:disabled:active,
@@ -606,16 +607,17 @@ input[type="checkbox"] {
    add up the way nsFormControlFrame::GetIntrinsic(Width|Height)
    expects them to, or they will not come out with total width equal
    to total height on sites that set their 'width' or 'height' to 'auto'.
    (Should we maybe set !important on width and height, then?)  */
 input[type="radio"],
 input[type="checkbox"] {
   inline-size: 13px;
   block-size: 13px;
+  color: -moz-FieldText;
   border: 2px inset ThreeDLightShadow;
   background-repeat: no-repeat;
   background-position: center;
 }
 
 input[type="radio"]:disabled,
 input[type="radio"]:disabled:active,
 input[type="radio"]:disabled:hover,
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_permission_original.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+
+<script src="http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest/file_WebRequest_permission_original.js"></script>
+<script>
+"use strict";
+
+window.parent.postMessage({
+  page: "original",
+  script: window.testScript,
+}, "*");
+</script>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_permission_original.js
@@ -0,0 +1,2 @@
+"use strict";
+window.testScript = "original";
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_permission_redirected.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+
+<script src="http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest/file_WebRequest_permission_original.js"></script>
+<script>
+"use strict";
+
+window.parent.postMessage({
+  page: "redirected",
+  script: window.testScript,
+}, "*");
+</script>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_permission_redirected.js
@@ -0,0 +1,2 @@
+"use strict";
+window.testScript = "redirected";
--- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
@@ -3,16 +3,20 @@ support-files =
   chrome_cleanup_script.js
   head.js
   file_mixed.html
   head_webrequest.js
   file_csp.html
   file_csp.html^headers^
   file_to_drawWindow.html
   file_WebRequest_page3.html
+  file_WebRequest_permission_original.html
+  file_WebRequest_permission_redirected.html
+  file_WebRequest_permission_original.js
+  file_WebRequest_permission_redirected.js
   file_webNavigation_clientRedirect.html
   file_webNavigation_clientRedirect_httpHeaders.html
   file_webNavigation_clientRedirect_httpHeaders.html^headers^
   file_webNavigation_frameClientRedirect.html
   file_webNavigation_frameRedirect.html
   file_webNavigation_manualSubframe.html
   file_webNavigation_manualSubframe_page1.html
   file_webNavigation_manualSubframe_page2.html
@@ -101,15 +105,16 @@ subsuite = webrequest
 subsuite = webrequest
 [test_ext_webrequest_filter.html]
 subsuite = webrequest
 [test_ext_webrequest_suspend.html]
 subsuite = webrequest
 [test_ext_webrequest_upload.html]
 skip-if = os == 'android' # Currently fails in emulator tests
 subsuite = webrequest
+[test_ext_webrequest_permission.html]
 [test_ext_webnavigation.html]
 subsuite = webnavigation
 [test_ext_webnavigation_filters.html]
 subsuite = webnavigation
 [test_ext_window_postMessage.html]
 [test_ext_subframes_privileges.html]
 [test_ext_xhr_capabilities.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_permission.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for content script</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="text/javascript">
+"use strict";
+
+add_task(function* test_permissions() {
+  function background() {
+    browser.webRequest.onBeforeRequest.addListener(details => {
+      if (details.url.includes("_original")) {
+        let redirectUrl = details.url
+                                 .replace("mochi.test:8888", "example.com")
+                                 .replace("_original", "_redirected");
+        return {redirectUrl};
+      }
+      return {};
+    }, {urls: ["<all_urls>"]}, ["blocking"]);
+  }
+
+  let extensionData = {
+    manifest: {
+      permissions: ["webRequest", "webRequestBlocking", "<all_urls>"],
+    },
+    background,
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+  yield extension.startup();
+
+  function* check() {
+    let iframe = document.createElement("iframe");
+    document.body.appendChild(iframe);
+
+    let promise = new Promise(resolve => {
+      let listener = event => {
+        window.removeEventListener("message", listener);
+        resolve(event.data);
+      };
+      window.addEventListener("message", listener);
+    });
+
+    iframe.setAttribute("src", "http://example.com/tests/toolkit/components/extensions/test/mochitest/file_WebRequest_permission_original.html");
+    let result = yield promise;
+    document.body.removeChild(iframe);
+    return result;
+  }
+
+  let results = yield check();
+  is(results.page, "redirected", "Regular webRequest redirect works on an unprivileged page");
+  is(results.script, "redirected", "Regular webRequest redirect works from an unprivileged page");
+
+  yield SpecialPowers.pushPrefEnv({
+    set: [["extensions.webapi.testing", true]],
+  });
+
+  results = yield check();
+  is(results.page, "original", "webRequest redirect fails on a privileged page");
+  is(results.script, "original", "webRequest redirect fails from a privileged page");
+
+  yield extension.unload();
+});
+</script>
+
+</body>
+</html>