Bug 1208951 - Part 7: Add a StyleAnimationValue::ComputeValues method to compute components of a shorthand. r=birtles
authorCameron McCormack <cam@mcc.id.au>
Thu, 22 Oct 2015 19:22:38 +1100
changeset 304132 e7ee6d330e9df46cba717bab81e6cb2c5df8f25d
parent 304131 4cb5d9910f54ea97aa1df0869359482b8868341f
child 304133 42e93722947bc51e3804dc1845df31e8535f2336
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles
bugs1208951
milestone44.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
Bug 1208951 - Part 7: Add a StyleAnimationValue::ComputeValues method to compute components of a shorthand. r=birtles
layout/style/StyleAnimationValue.cpp
layout/style/StyleAnimationValue.h
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -2527,17 +2527,17 @@ LookupStyleContext(dom::Element* aElemen
   nsIDocument* doc = aElement->GetCurrentDoc();
   nsIPresShell* shell = doc->GetShell();
   if (!shell) {
     return nullptr;
   }
   return nsComputedDOMStyle::GetStyleContextForElement(aElement, nullptr, shell);
 }
 
-bool
+/* static */ bool
 StyleAnimationValue::ComputeValue(nsCSSProperty aProperty,
                                   dom::Element* aTargetElement,
                                   const nsAString& aSpecifiedValue,
                                   bool aUseSVGMode,
                                   StyleAnimationValue& aComputedValue,
                                   bool* aIsContextSensitive)
 {
   MOZ_ASSERT(aTargetElement, "null target element");
@@ -2559,65 +2559,141 @@ StyleAnimationValue::ComputeValue(nsCSSP
     if (aIsContextSensitive) {
       // Since we're just returning the string as-is, aComputedValue isn't going
       // to change depending on the context
       *aIsContextSensitive = false;
     }
     return true;
   }
 
+  nsAutoTArray<PropertyStyleAnimationValuePair,1> values;
+  bool ok = ComputeValues(aProperty, nsCSSProps::eIgnoreEnabledState,
+                          aTargetElement, styleRule, values,
+                          aIsContextSensitive);
+  if (!ok) {
+    return false;
+  }
+
+  MOZ_ASSERT(values.Length() == 1);
+  MOZ_ASSERT(values[0].mProperty == aProperty);
+
+  aComputedValue = values[0].mValue;
+  return true;
+}
+
+/* static */ bool
+StyleAnimationValue::ComputeValues(nsCSSProperty aProperty,
+                                   nsCSSProps::EnabledState aEnabledState,
+                                   dom::Element* aTargetElement,
+                                   const nsAString& aSpecifiedValue,
+                                   bool aUseSVGMode,
+                                   nsTArray<PropertyStyleAnimationValuePair>& aResult)
+{
+  MOZ_ASSERT(aTargetElement, "null target element");
+  MOZ_ASSERT(aTargetElement->GetCurrentDoc(),
+             "we should only be able to actively animate nodes that "
+             "are in a document");
+
+  // Parse specified value into a temporary css::StyleRule
+  RefPtr<css::StyleRule> styleRule =
+    BuildStyleRule(aProperty, aTargetElement, aSpecifiedValue, aUseSVGMode);
+  if (!styleRule) {
+    return false;
+  }
+
+  aResult.Clear();
+  return ComputeValues(aProperty, aEnabledState, aTargetElement, styleRule,
+                       aResult, /* aIsContextSensitive */ nullptr);
+}
+
+/* static */ bool
+StyleAnimationValue::ComputeValues(
+    nsCSSProperty aProperty,
+    nsCSSProps::EnabledState aEnabledState,
+    dom::Element* aTargetElement,
+    css::StyleRule* aStyleRule,
+    nsTArray<PropertyStyleAnimationValuePair>& aValues,
+    bool* aIsContextSensitive)
+{
+  if (!nsCSSProps::IsEnabled(aProperty, aEnabledState)) {
+    return false;
+  }
+
   // Look up style context for our target element
   RefPtr<nsStyleContext> styleContext = LookupStyleContext(aTargetElement);
   if (!styleContext) {
     return false;
   }
   nsStyleSet* styleSet = styleContext->PresContext()->StyleSet();
 
   RefPtr<nsStyleContext> tmpStyleContext;
   if (aIsContextSensitive) {
+    MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
+               "to correctly set aIsContextSensitive for shorthand properties, "
+               "this code must be adjusted");
+
     nsCOMArray<nsIStyleRule> ruleArray;
     ruleArray.AppendObject(styleSet->InitialStyleRule());
-    ruleArray.AppendObject(styleRule);
-    styleRule->RuleMatched();
+    ruleArray.AppendObject(aStyleRule);
+    aStyleRule->RuleMatched();
     tmpStyleContext =
       styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
     if (!tmpStyleContext) {
       return false;
     }
 
     // Force walk of rule tree
     nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty];
     tmpStyleContext->StyleData(sid);
 
-    // If the rule node will have cached style data if the value is not
-    // context-sensitive. So if there's nothing cached, it's not context
+    // The rule node will have unconditional cached style data if the value is
+    // not context-sensitive.  So if there's nothing cached, it's not context
     // sensitive.
     *aIsContextSensitive =
       !tmpStyleContext->RuleNode()->NodeHasCachedUnconditionalData(sid);
   }
 
   // If we're not concerned whether the property is context sensitive then just
   // add the rule to a new temporary style context alongside the target
   // element's style context.
   // Also, if we previously discovered that this property IS context-sensitive
   // then we need to throw the temporary style context out since the property's
   // value may have been biased by the 'initial' values supplied.
   if (!aIsContextSensitive || *aIsContextSensitive) {
     nsCOMArray<nsIStyleRule> ruleArray;
-    ruleArray.AppendObject(styleRule);
-    styleRule->RuleMatched();
+    ruleArray.AppendObject(aStyleRule);
+    aStyleRule->RuleMatched();
     tmpStyleContext =
       styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
     if (!tmpStyleContext) {
       return false;
     }
   }
 
-  // Extract computed value of our property from the temporary style rule
-  return ExtractComputedValue(aProperty, tmpStyleContext, aComputedValue);
+  // Extract computed value of our property (or all longhand components, if
+  // aProperty is a shorthand) from the temporary style rule
+  if (nsCSSProps::IsShorthand(aProperty)) {
+    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty, aEnabledState) {
+      if (nsCSSProps::kAnimTypeTable[*p] == eStyleAnimType_None) {
+        // Skip non-animatable component longhands.
+        continue;
+      }
+      PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
+      pair->mProperty = *p;
+      if (!ExtractComputedValue(*p, tmpStyleContext,
+                                pair->mValue)) {
+        return false;
+      }
+    }
+    return true;
+  } else {
+    PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
+    pair->mProperty = aProperty;
+    return ExtractComputedValue(aProperty, tmpStyleContext, pair->mValue);
+  }
 }
 
 bool
 StyleAnimationValue::UncomputeValue(nsCSSProperty aProperty,
                                     const StyleAnimationValue& aComputedValue,
                                     nsCSSValue& aSpecifiedValue)
 {
   Unit unit = aComputedValue.GetUnit();
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -5,35 +5,41 @@
 
 /* Utilities for animation of computed style values */
 
 #ifndef mozilla_StyleAnimationValue_h_
 #define mozilla_StyleAnimationValue_h_
 
 #include "nsStringFwd.h"
 #include "nsStringBuffer.h"
-#include "nsCSSProperty.h"
 #include "nsCoord.h"
 #include "nsColor.h"
+#include "nsCSSProps.h"
 #include "nsCSSValue.h"
 
 class nsIFrame;
 class nsStyleContext;
 class gfx3DMatrix;
 
 namespace mozilla {
 
+namespace css {
+class StyleRule;
+} // namespace css
+
 namespace dom {
 class Element;
 } // namespace dom
 
 namespace gfx {
 class Matrix4x4;
 } // namespace gfx
 
+struct PropertyStyleAnimationValuePair;
+
 /**
  * Utility class to handle animated style values
  */
 class StyleAnimationValue {
 public:
   // Mathematical methods
   // --------------------
   /**
@@ -149,16 +155,33 @@ public:
   static bool ComputeValue(nsCSSProperty aProperty,
                              mozilla::dom::Element* aTargetElement,
                              const nsAString& aSpecifiedValue,
                              bool aUseSVGMode,
                              StyleAnimationValue& aComputedValue,
                              bool* aIsContextSensitive = nullptr);
 
   /**
+   * Like ComputeValue, but returns an array of StyleAnimationValues.
+   *
+   * On success, when aProperty is a longhand, aResult will have a single
+   * value in it.  When aProperty is a shorthand, aResult will be filled with
+   * values for all of aProperty's longhand components.  aEnabledState
+   * is used to filter the longhand components that will be appended
+   * to aResult.  On failure, aResult might still have partial results
+   * in it.
+   */
+  static bool ComputeValues(nsCSSProperty aProperty,
+                            nsCSSProps::EnabledState aEnabledState,
+                            mozilla::dom::Element* aTargetElement,
+                            const nsAString& aSpecifiedValue,
+                            bool aUseSVGMode,
+                            nsTArray<PropertyStyleAnimationValuePair>& aResult);
+
+  /**
    * Creates a specified value for the given computed value.
    *
    * The first overload fills in an nsCSSValue object; the second
    * produces a string.  The nsCSSValue result may depend on objects
    * owned by the |aComputedValue| object, so users of that variant
    * must keep |aComputedValue| alive longer than |aSpecifiedValue|.
    *
    * @param aProperty      The property whose value we're uncomputing.
@@ -368,16 +391,23 @@ public:
 
   StyleAnimationValue& operator=(const StyleAnimationValue& aOther);
 
   bool operator==(const StyleAnimationValue& aOther) const;
   bool operator!=(const StyleAnimationValue& aOther) const
     { return !(*this == aOther); }
 
 private:
+  static bool ComputeValues(nsCSSProperty aProperty,
+                            nsCSSProps::EnabledState aEnabledState,
+                            mozilla::dom::Element* aTargetElement,
+                            mozilla::css::StyleRule* aStyleRule,
+                            nsTArray<PropertyStyleAnimationValuePair>& aValues,
+                            bool* aIsContextSensitive);
+
   void FreeValue();
 
   static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) {
     return static_cast<char16_t*>(aBuffer->Data());
   }
 
   static bool IsIntUnit(Unit aUnit) {
     return aUnit == eUnit_Enumerated || aUnit == eUnit_Visibility ||
@@ -407,11 +437,17 @@ private:
   static bool IsCSSValuePairListUnit(Unit aUnit) {
     return aUnit == eUnit_CSSValuePairList;
   }
   static bool IsStringUnit(Unit aUnit) {
     return aUnit == eUnit_UnparsedString;
   }
 };
 
+struct PropertyStyleAnimationValuePair
+{
+  nsCSSProperty mProperty;
+  StyleAnimationValue mValue;
+};
+
 } // namespace mozilla
 
 #endif