Bug 1248340 - Part 4: Implement Frames in the style system. draft
authorBoris Chiou <boris.chiou@gmail.com>
Fri, 24 Feb 2017 14:50:08 +0800
changeset 495027 7f9837fdc192d211b76a924682c28a29592fbba1
parent 495026 546b4060e723e7df29fde9d17a025216998f06cf
child 495028 12ebc4952780373f0478253d07f00bf148a8bd4b
push id48204
push userbmo:boris.chiou@gmail.com
push dateWed, 08 Mar 2017 05:44:16 +0000
bugs1248340
milestone55.0a1
Bug 1248340 - Part 4: Implement Frames in the style system. Use eCSSUnit_Function to store the frames timing function. Also, add one more css keyword: frames. The following changes are included in this: 1. Parser changes. 2. Serialization. 3. Computation in nsRuleNode. 4. Invalid and other values in property_database.js MozReview-Commit-ID: 887QcXHQ2pU
dom/animation/ComputedTimingFunction.cpp
dom/animation/TimingParams.cpp
layout/style/nsCSSKeywordList.h
layout/style/nsCSSParser.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleUtil.cpp
layout/style/nsStyleUtil.h
layout/style/test/property_database.js
--- a/dom/animation/ComputedTimingFunction.cpp
+++ b/dom/animation/ComputedTimingFunction.cpp
@@ -167,17 +167,17 @@ ComputedTimingFunction::AppendToString(n
                                                    mTimingFunction.Y2(),
                                                    aResult);
       break;
     case nsTimingFunction::Type::StepStart:
     case nsTimingFunction::Type::StepEnd:
       nsStyleUtil::AppendStepsTimingFunction(mType, mStepsOrFrames, aResult);
       break;
     case nsTimingFunction::Type::Frames:
-      // TODO: Serialize Frames timing function.
+      nsStyleUtil::AppendFramesTimingFunction(mStepsOrFrames, aResult);
       break;
     default:
       nsStyleUtil::AppendCubicBezierKeywordTimingFunction(mType, aResult);
       break;
   }
 }
 
 /* static */ int32_t
--- a/dom/animation/TimingParams.cpp
+++ b/dom/animation/TimingParams.cpp
@@ -133,16 +133,17 @@ TimingParams::ParseEasing(const nsAStrin
         case eCSSUnit_Enumerated:
           // Return Nothing() if "linear" is passed in.
           if (list->mValue.GetIntValue() ==
               NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR) {
             return Nothing();
           }
           MOZ_FALLTHROUGH;
         case eCSSUnit_Cubic_Bezier:
+        case eCSSUnit_Function:
         case eCSSUnit_Steps: {
           nsTimingFunction timingFunction;
           nsRuleNode::ComputeTimingFunction(list->mValue, timingFunction);
           ComputedTimingFunction computedTimingFunction;
           computedTimingFunction.Init(timingFunction);
           return Some(computedTimingFunction);
         }
         default:
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -280,16 +280,17 @@ CSS_KEY(fixed, fixed)
 CSS_KEY(flat, flat)
 CSS_KEY(flex, flex)
 CSS_KEY(flex-end, flex_end)
 CSS_KEY(flex-start, flex_start)
 CSS_KEY(flip, flip)
 CSS_KEY(flow-root, flow_root)
 CSS_KEY(forwards, forwards)
 CSS_KEY(fraktur, fraktur)
+CSS_KEY(frames, frames)
 CSS_KEY(from-image, from_image)
 CSS_KEY(full-width, full_width)
 CSS_KEY(fullscreen, fullscreen)
 CSS_KEY(grab, grab)
 CSS_KEY(grabbing, grabbing)
 CSS_KEY(grad, grad)
 CSS_KEY(grayscale, grayscale)
 CSS_KEY(graytext, graytext)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -1064,16 +1064,17 @@ protected:
   bool ParseShadowList(nsCSSPropertyID aProperty);
   bool ParseShapeOutside(nsCSSValue& aValue);
   bool ParseTransitionProperty();
   bool ParseTransitionTimingFunctionValues(nsCSSValue& aValue);
   bool ParseTransitionTimingFunctionValueComponent(float& aComponent,
                                                      char aStop,
                                                      bool aIsXPoint);
   bool ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue);
+  bool ParseTransitionFramesTimingFunctionValues(nsCSSValue& aValue);
   enum ParseAnimationOrTransitionShorthandResult {
     eParseAnimationOrTransitionShorthand_Values,
     eParseAnimationOrTransitionShorthand_Inherit,
     eParseAnimationOrTransitionShorthand_Error
   };
   ParseAnimationOrTransitionShorthandResult
     ParseAnimationOrTransitionShorthand(const nsCSSPropertyID* aProperties,
                                         const nsCSSValue* aInitialValues,
@@ -7938,16 +7939,23 @@ CSSParserImpl::ParseVariant(nsCSSValue& 
     }
     if (tk->mIdent.LowerCaseEqualsLiteral("steps")) {
       if (!ParseTransitionStepTimingFunctionValues(aValue)) {
         SkipUntil(')');
         return CSSParseResult::Error;
       }
       return CSSParseResult::Ok;
     }
+    if (tk->mIdent.LowerCaseEqualsLiteral("frames")) {
+      if (!ParseTransitionFramesTimingFunctionValues(aValue)) {
+        SkipUntil(')');
+        return CSSParseResult::Error;
+      }
+      return CSSParseResult::Ok;
+    }
   }
   if ((aVariantMask & VARIANT_CALC) &&
       IsCSSTokenCalcFunction(*tk)) {
     // calc() currently allows only lengths, percents, numbers, and integers.
     //
     // Note that VARIANT_NUMBER can be mixed with VARIANT_LENGTH and
     // VARIANT_PERCENTAGE in the list of allowed types (numbers can be used as
     // coefficients).
@@ -16796,16 +16804,49 @@ CSSParserImpl::ParseTransitionStepTiming
   if (!ExpectSymbol(')', true)) {
     return false;
   }
 
   aValue.SetArrayValue(val, eCSSUnit_Steps);
   return true;
 }
 
+bool
+CSSParserImpl::ParseTransitionFramesTimingFunctionValues(nsCSSValue& aValue)
+{
+  NS_ASSERTION(!mHavePushBack &&
+               mToken.mType == eCSSToken_Function &&
+               mToken.mIdent.LowerCaseEqualsLiteral("frames"),
+               "unexpected initial state");
+
+  nsCSSKeyword functionName = nsCSSKeywords::LookupKeyword(mToken.mIdent);
+  MOZ_ASSERT(functionName == eCSSKeyword_frames);
+
+  nsCSSValue frameNumber;
+  if (!ParseSingleTokenOneOrLargerVariant(frameNumber, VARIANT_INTEGER,
+                                          nullptr)) {
+    return false;
+  }
+  MOZ_ASSERT(frameNumber.GetIntValue() >= 1,
+             "Parsing function should've enforced OneOrLarger, per its name");
+
+  // The number of frames must be a positive integer greater than one.
+  if (frameNumber.GetIntValue() == 1) {
+    return false;
+  }
+
+  if (!ExpectSymbol(')', true)) {
+    return false;
+  }
+
+  RefPtr<nsCSSValue::Array> val = aValue.InitFunction(functionName, 1);
+  val->Item(1) = frameNumber;
+  return true;
+}
+
 static nsCSSValueList*
 AppendValueToList(nsCSSValue& aContainer,
                   nsCSSValueList* aTail,
                   const nsCSSValue& aValue)
 {
   nsCSSValueList* entry;
   if (aContainer.GetUnit() == eCSSUnit_Null) {
     MOZ_ASSERT(!aTail, "should not have an entry");
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -6566,16 +6566,20 @@ nsComputedDOMStyle::AppendTimingFunction
                                                    tmp);
       break;
     case nsTimingFunction::Type::StepStart:
     case nsTimingFunction::Type::StepEnd:
       nsStyleUtil::AppendStepsTimingFunction(aTimingFunction.mType,
                                              aTimingFunction.mStepsOrFrames,
                                              tmp);
       break;
+    case nsTimingFunction::Type::Frames:
+      nsStyleUtil::AppendFramesTimingFunction(aTimingFunction.mStepsOrFrames,
+                                              tmp);
+      break;
     default:
       nsStyleUtil::AppendCubicBezierKeywordTimingFunction(aTimingFunction.mType,
                                                           tmp);
       break;
   }
   timingFunction->SetString(tmp);
   aValueList->AppendCSSValue(timingFunction.forget());
 }
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5512,16 +5512,28 @@ nsRuleNode::ComputeTimingFunction(const 
         nsTimingFunction::Type type =
           (array->Item(1).GetIntValue() ==
             NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START) ?
               nsTimingFunction::Type::StepStart :
               nsTimingFunction::Type::StepEnd;
         aResult = nsTimingFunction(type, array->Item(0).GetIntValue());
       }
       break;
+    case eCSSUnit_Function:
+      {
+        nsCSSValue::Array* array = aValue.GetArrayValue();
+        NS_ASSERTION(array && array->Count() == 2, "Need 2 items");
+        NS_ASSERTION(array->Item(0).GetKeywordValue() == eCSSKeyword_frames,
+                     "should be frames function");
+        NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Integer,
+                     "unexpected frames function value");
+        aResult = nsTimingFunction(nsTimingFunction::Type::Frames,
+                                   array->Item(1).GetIntValue());
+      }
+      break;
     default:
       NS_NOTREACHED("Invalid transition property unit");
   }
 }
 
 static uint8_t
 GetWillChangeBitFieldFromPropFlags(const nsCSSPropertyID& aProp)
 {
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -652,16 +652,25 @@ nsStyleUtil::AppendStepsTimingFunction(n
   if (aType == nsTimingFunction::Type::StepStart) {
     aResult.AppendLiteral(", start)");
   } else {
     aResult.AppendLiteral(")");
   }
 }
 
 /* static */ void
+nsStyleUtil::AppendFramesTimingFunction(uint32_t aFrames,
+                                        nsAString& aResult)
+{
+  aResult.AppendLiteral("frames(");
+  aResult.AppendInt(aFrames);
+  aResult.AppendLiteral(")");
+}
+
+/* static */ void
 nsStyleUtil::AppendCubicBezierTimingFunction(float aX1, float aY1,
                                              float aX2, float aY2,
                                              nsAString& aResult)
 {
   // set the value from the cubic-bezier control points
   // (We could try to regenerate the keywords if we want.)
   aResult.AppendLiteral("cubic-bezier(");
   aResult.AppendFloat(aX1);
--- a/layout/style/nsStyleUtil.h
+++ b/layout/style/nsStyleUtil.h
@@ -82,16 +82,18 @@ public:
   static void AppendCSSNumber(float aNumber, nsAString& aResult)
   {
     aResult.AppendFloat(aNumber);
   }
 
   static void AppendStepsTimingFunction(nsTimingFunction::Type aType,
                                         uint32_t aSteps,
                                         nsAString& aResult);
+  static void AppendFramesTimingFunction(uint32_t aFrames,
+                                         nsAString& aResult);
   static void AppendCubicBezierTimingFunction(float aX1, float aY1,
                                               float aX2, float aY2,
                                               nsAString& aResult);
   static void AppendCubicBezierKeywordTimingFunction(
       nsTimingFunction::Type aType,
       nsAString& aResult);
 
   static void AppendSerializedFontSrc(const nsCSSValue& aValue,
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -968,18 +968,18 @@ var gCSSProperties = {
     other_values: [ "paused", "running, running", "paused, running", "paused, paused", "running, paused", "paused, running, running, running, paused, running" ],
     invalid_values: [ "0" ]
   },
   "animation-timing-function": {
     domProp: "animationTimingFunction",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "ease" ],
-    other_values: [ "cubic-bezier(0.25, 0.1, 0.25, 1.0)", "linear", "ease-in", "ease-out", "ease-in-out", "linear, ease-in, cubic-bezier(0.1, 0.2, 0.8, 0.9)", "cubic-bezier(0.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.25, 1.5, 0.75, -0.5)", "step-start", "step-end", "steps(1)", "steps(2, start)", "steps(386)", "steps(3, end)" ],
-    invalid_values: [ "none", "auto", "cubic-bezier(0.25, 0.1, 0.25)", "cubic-bezier(0.25, 0.1, 0.25, 0.25, 1.0)", "cubic-bezier(-0.5, 0.5, 0.5, 0.5)", "cubic-bezier(1.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.5, 0.5, -0.5, 0.5)", "cubic-bezier(0.5, 0.5, 1.5, 0.5)", "steps(2, step-end)", "steps(0)", "steps(-2)", "steps(0, step-end, 1)" ]
+    other_values: [ "cubic-bezier(0.25, 0.1, 0.25, 1.0)", "linear", "ease-in", "ease-out", "ease-in-out", "linear, ease-in, cubic-bezier(0.1, 0.2, 0.8, 0.9)", "cubic-bezier(0.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.25, 1.5, 0.75, -0.5)", "step-start", "step-end", "steps(1)", "steps(2, start)", "steps(386)", "steps(3, end)", "frames(2)", "frames(1000)", "frames( 2 )" ],
+    invalid_values: [ "none", "auto", "cubic-bezier(0.25, 0.1, 0.25)", "cubic-bezier(0.25, 0.1, 0.25, 0.25, 1.0)", "cubic-bezier(-0.5, 0.5, 0.5, 0.5)", "cubic-bezier(1.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.5, 0.5, -0.5, 0.5)", "cubic-bezier(0.5, 0.5, 1.5, 0.5)", "steps(2, step-end)", "steps(0)", "steps(-2)", "steps(0, step-end, 1)", "frames(1)", "frames(-2)", "frames", "frames()", "frames(,)", "frames(a)", "frames(2.0)", "frames(2.5)", "frames(2 3)" ]
   },
   "-moz-appearance": {
     domProp: "MozAppearance",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "none" ],
     other_values: [ "radio", "menulist" ],
     invalid_values: []